unique-search-proxy-core 2026.30.0.dev0__tar.gz → 2026.30.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.
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/PKG-INFO +59 -90
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/README.md +57 -88
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/pyproject.toml +2 -2
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/base.py +26 -1
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/bing/schema.py +6 -9
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/config_types.py +3 -6
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/vertexai/schema.py +5 -9
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/base.py +20 -1
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/basic/schema.py +4 -3
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/config_types.py +2 -7
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/firecrawl/schema.py +4 -3
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/jina/schema.py +4 -3
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/params.py +4 -6
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/tavily/schema.py +4 -3
- unique_search_proxy_core-2026.30.0.dev2/unique_search_proxy_core/param_policy/__init__.py +24 -0
- unique_search_proxy_core-2026.30.0.dev2/unique_search_proxy_core/param_policy/annotations.py +135 -0
- unique_search_proxy_core-2026.30.0.dev2/unique_search_proxy_core/param_policy/derive.py +119 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/param_policy/exposable_param.py +15 -26
- unique_search_proxy_core-2026.30.0.dev2/unique_search_proxy_core/param_policy/exposed_params.py +66 -0
- unique_search_proxy_core-2026.30.0.dev2/unique_search_proxy_core/param_policy/request_base.py +37 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/search_engines/__init__.py +0 -8
- unique_search_proxy_core-2026.30.0.dev2/unique_search_proxy_core/search_engines/base.py +218 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/search_engines/brave/__init__.py +0 -2
- unique_search_proxy_core-2026.30.0.dev2/unique_search_proxy_core/search_engines/brave/schema.py +332 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/search_engines/config_types.py +3 -4
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/search_engines/google/__init__.py +0 -2
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/search_engines/google/schema.py +28 -48
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/search_engines/perplexity/__init__.py +0 -2
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/search_engines/perplexity/schema.py +36 -71
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/agent_engines/projection.py +0 -47
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/crawlers/projection.py +0 -43
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/model_derivation/__init__.py +0 -21
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/model_derivation/derive.py +0 -52
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/model_derivation/fields.py +0 -144
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/param_policy/__init__.py +0 -21
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/param_policy/policy.py +0 -3
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/projection.py +0 -133
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/search_engines/base.py +0 -114
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/search_engines/brave/schema.py +0 -178
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/search_engines/call_schema.py +0 -78
- unique_search_proxy_core-2026.30.0.dev0/unique_search_proxy_core/search_engines/params.py +0 -99
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/__init__.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/__init__.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/bing/__init__.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/output_schema.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/resolve.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/response_parsing.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/agent_engines/vertexai/__init__.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/__init__.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/basic/__init__.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/basic/content_types.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/crawlers/basic/processing/policy.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/errors.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/logging.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/providers/schema.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/schema.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/__init__.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/dns.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/egress.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/models.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/netloc.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/policy.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/redirect.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/resolver.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/service.py +0 -0
- {unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/unique_search_proxy_core/url_safety/settings.py +0 -0
{unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-search-proxy-core
|
|
3
|
-
Version: 2026.30.0.
|
|
3
|
+
Version: 2026.30.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.30.0.
|
|
11
|
+
Requires-Dist: unique-toolkit[monitoring]>=2026.30.0.dev10,<2026.30.0rc0
|
|
12
12
|
Requires-Python: >=3.12
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
|
|
@@ -46,17 +46,15 @@ flowchart TB
|
|
|
46
46
|
|
|
47
47
|
subgraph core["unique_search_proxy_core"]
|
|
48
48
|
Contracts["Response & error models"]
|
|
49
|
-
Config["*Config deployment models"]
|
|
50
|
-
Project["Schema projection & merge"]
|
|
49
|
+
Config["*Config deployment models\n(request_model / exposed_params_model / merge)"]
|
|
51
50
|
end
|
|
52
51
|
|
|
53
52
|
AC --> Config
|
|
54
|
-
AC --> Project
|
|
55
53
|
Client --> Contracts
|
|
56
54
|
Client --> Config
|
|
57
55
|
SDK --> Contracts
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
Config -->|"flat request body"| SDK
|
|
57
|
+
Config -->|"flat request body"| Client
|
|
60
58
|
```
|
|
61
59
|
|
|
62
60
|
System overview → [../README.md](../README.md)
|
|
@@ -65,81 +63,63 @@ System overview → [../README.md](../README.md)
|
|
|
65
63
|
|
|
66
64
|
## 3. Key concepts
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
**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.
|
|
69
67
|
|
|
70
|
-
### 3.1
|
|
68
|
+
### 3.1 Config-owned API (search engines)
|
|
71
69
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```mermaid
|
|
79
|
-
flowchart TB
|
|
80
|
-
subgraph search["Search engines only"]
|
|
81
|
-
GC["GoogleConfig\n(ExposableParam knobs)"]
|
|
82
|
-
Proj["projection.py\nbuild_request_model\nbuild_llm_call_model"]
|
|
83
|
-
GSR["GoogleSearchRequest"]
|
|
84
|
-
LLM["LLM call schema"]
|
|
85
|
-
GC --> Proj
|
|
86
|
-
Proj --> GSR
|
|
87
|
-
Proj --> LLM
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
subgraph agent["Agent engines"]
|
|
91
|
-
BC["BingAgentConfig\n(plain fields)"]
|
|
92
|
-
AProj["agent_engines/projection.py\nbuild_agent_request_model"]
|
|
93
|
-
BSR["BingAgentSearchRequest"]
|
|
94
|
-
BC --> AProj
|
|
95
|
-
AProj -->|"via model_derivation"| BSR
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
subgraph crawl["Crawlers"]
|
|
99
|
-
BCrawl["BasicConfig\n(no urls)"]
|
|
100
|
-
CProj["crawlers/projection.py\nbuild_crawl_request_model"]
|
|
101
|
-
BCR["BasicCrawlRequest\n(urls injected)"]
|
|
102
|
-
BCrawl --> CProj
|
|
103
|
-
CProj -->|"via model_derivation"| BCR
|
|
104
|
-
end
|
|
70
|
+
```
|
|
71
|
+
Admin JSON → GoogleConfig {expose, value}
|
|
72
|
+
├─ GoogleConfig.request_model() → GoogleSearchRequest (HTTP body, query required)
|
|
73
|
+
├─ config.exposed_params_model() → GoogleExposedParams (LLM knobs; tool inherits it)
|
|
74
|
+
├─ config.merge(llm_args, query=…) → validated GoogleSearchRequest
|
|
75
|
+
└─ GoogleConfig.provider_query_params(req) → upstream provider dict
|
|
105
76
|
```
|
|
106
77
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
|
112
|
-
|
|
113
|
-
| **Deployment config** | Admin / deployment UI | `{ "engine": "google", "gl": { "expose": true, "value": "de" }, … }` |
|
|
114
|
-
| **LLM call schema** | Tool manifest shown to the model | `{ "query", "gl" }` — only fields where `expose: true` |
|
|
115
|
-
| **HTTP request body** | `POST /v1/search` wire format | `{ "engine": "google", "query": "…", "gl": "de", "fetchSize": 10 }` |
|
|
78
|
+
| Method | Kind | Returns |
|
|
79
|
+
|--------|------|---------|
|
|
80
|
+
| `request_model()` (classmethod, cached) | search / agent / crawl | `SearchRequestBase` (required `query`) or `CrawlRequestBase` (required `urls`) + config fields; `ExposableParam` knobs unwrapped to optional plain types |
|
|
81
|
+
| `exposed_params_model()` (instance) | search only | `ExposedParams` subclass with exactly the `expose=True` knobs (camelCase aliases, description-only schema), or `None` |
|
|
82
|
+
| `merge(overrides, *, query)` (instance) | search only | deployment defaults + LLM overrides + query → validated `request_model()` instance |
|
|
83
|
+
| `provider_query_params(request)` (classmethod) | search only | request serialized for the upstream provider, minus `_provider_param_exclude_fields` (Google adds `search_engine_id`) |
|
|
116
84
|
|
|
117
|
-
|
|
85
|
+
Agent engines (`BingAgentConfig`, …) and crawlers (`BasicConfig`, …) only implement `request_model()`; crawlers additionally keep `merge_crawler_config_and_invocation`.
|
|
118
86
|
|
|
119
|
-
### 3.
|
|
87
|
+
### 3.2 ExposableParam — search-engine only
|
|
120
88
|
|
|
121
89
|
Optional **search** parameters use `ExposableParam[T]`:
|
|
122
90
|
|
|
123
91
|
- **`value`** — admin default merged into every request (`null` = deactivated)
|
|
124
|
-
- **`expose`** — when `true`, the parameter appears on the LLM
|
|
92
|
+
- **`expose`** — when `true`, the parameter appears on the LLM-facing exposed-params model
|
|
125
93
|
|
|
126
94
|
```python
|
|
127
95
|
gl: ExposableParam[str | None] = ExposableParam(expose=False, value="de") # admin-fixed
|
|
128
96
|
gl: ExposableParam[str | None] = ExposableParam(expose=True, value=None) # LLM-overridable
|
|
129
97
|
```
|
|
130
98
|
|
|
131
|
-
|
|
99
|
+
Bare scalars are **not** coerced — deployment JSON must use the explicit `{"expose": …, "value": …}` shape.
|
|
100
|
+
|
|
101
|
+
### 3.3 ExposedParams — the LLM tool-schema contract
|
|
132
102
|
|
|
133
|
-
|
|
103
|
+
`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:
|
|
134
104
|
|
|
135
105
|
```python
|
|
136
|
-
|
|
106
|
+
Exposed = config.exposed_params_model() # GoogleExposedParams | None
|
|
107
|
+
class ToolParams(ToolParamsBase, Exposed): ... # or create_model(__base__=(...))
|
|
108
|
+
|
|
109
|
+
ToolParams.model_json_schema() # camelCase knobs, no title/default noise
|
|
110
|
+
Exposed.model_fields # the exposed field names
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
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.
|
|
137
114
|
|
|
138
|
-
|
|
115
|
+
### 3.4 merge — deployment defaults + LLM overrides
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
request = google_config.merge({"gl": "de"}, query="EU AI Act")
|
|
139
119
|
# → validated GoogleSearchRequest ready for POST /v1/search
|
|
140
120
|
```
|
|
141
121
|
|
|
142
|
-
The proxy receives a flat body; it does not resolve deployment config over HTTP.
|
|
122
|
+
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.
|
|
143
123
|
|
|
144
124
|
### 3.5 merge_crawler_config_and_invocation — crawler only
|
|
145
125
|
|
|
@@ -159,25 +139,16 @@ flowchart TB
|
|
|
159
139
|
subgraph core_pkg["unique_search_proxy_core"]
|
|
160
140
|
Schema["schema.py"]
|
|
161
141
|
Errors["errors.py"]
|
|
162
|
-
|
|
163
|
-
PP["param_policy/"]
|
|
164
|
-
Proj["projection.py\n(search + LLM projection)"]
|
|
165
|
-
AProj["agent_engines/projection.py"]
|
|
166
|
-
CProj["crawlers/projection.py"]
|
|
142
|
+
PP["param_policy/\nExposableParam · ExposedParams\nrequest bases · derive"]
|
|
167
143
|
Prov["providers/schema.py"]
|
|
168
144
|
SE["search_engines/"]
|
|
169
145
|
AE["agent_engines/"]
|
|
170
146
|
CR["crawlers/"]
|
|
171
147
|
end
|
|
172
148
|
|
|
173
|
-
PP --> Proj
|
|
174
149
|
PP --> SE
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
MD --> CProj
|
|
178
|
-
Proj --> SE
|
|
179
|
-
AProj --> AE
|
|
180
|
-
CProj --> CR
|
|
150
|
+
PP --> AE
|
|
151
|
+
PP --> CR
|
|
181
152
|
Prov --> SE
|
|
182
153
|
Prov --> CR
|
|
183
154
|
SE --> Schema
|
|
@@ -190,15 +161,15 @@ flowchart TB
|
|
|
190
161
|
|--------|----------------|
|
|
191
162
|
| `schema.py` | Shared API models: `SearchResponse`, `AgentSearchResponse`, `CrawlResponse`, `WebSearchResult`, `ErrorResponse`, SSE events |
|
|
192
163
|
| `errors.py` | `ProxyError` hierarchy and stable `ProxyErrorCode` enum |
|
|
193
|
-
| `
|
|
194
|
-
| `param_policy
|
|
195
|
-
| `
|
|
196
|
-
| `
|
|
197
|
-
| `
|
|
164
|
+
| `param_policy/exposable_param.py` | `ExposableParam` value object, factory-default merge, type introspection, OpenAPI naming |
|
|
165
|
+
| `param_policy/exposed_params.py` | `ExposedParams` base for LLM-facing parameter models (schema noise stripping) |
|
|
166
|
+
| `param_policy/request_base.py` | `SearchRequestBase` / `AgentRequestBase` / `CrawlRequestBase` (required leading fields) |
|
|
167
|
+
| `param_policy/annotations.py` | Annotation unwrapping helpers (private, used by `derive`) |
|
|
168
|
+
| `param_policy/derive.py` | `derive_request_model` / `derive_exposed_params_model` factories called by the config base classes |
|
|
198
169
|
| `providers/schema.py` | JSON Schema + defaults for deployment UIs (`provider_config_json_schema`, …) |
|
|
199
|
-
| `search_engines/` | Config models
|
|
200
|
-
| `agent_engines/` | Agent config/request models, output schema |
|
|
201
|
-
| `crawlers/` | `*Config` deployment models + derived `*CrawlRequest`
|
|
170
|
+
| `search_engines/` | Config models with the config-owned API (`request_model` / `exposed_params_model` / `merge` / `provider_query_params`), request union |
|
|
171
|
+
| `agent_engines/` | Agent config/request models (`request_model`), output schema |
|
|
172
|
+
| `crawlers/` | `*Config` deployment models + derived `*CrawlRequest` bodies, `merge_crawler_config_and_invocation` |
|
|
202
173
|
|
|
203
174
|
---
|
|
204
175
|
|
|
@@ -230,21 +201,19 @@ schema = provider_config_json_schema("search_engine", "google")
|
|
|
230
201
|
defaults = provider_default_config("search_engine", "google")
|
|
231
202
|
```
|
|
232
203
|
|
|
233
|
-
### Tool manifest — LLM
|
|
204
|
+
### Tool manifest — exposed LLM knobs
|
|
234
205
|
|
|
235
206
|
```python
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
# descriptor.call_schema → JSON Schema for the LLM tool
|
|
207
|
+
Exposed = google_config.exposed_params_model() # GoogleExposedParams | None
|
|
208
|
+
class ToolParams(ToolParamsBase, Exposed): ... # graft knobs by inheritance
|
|
209
|
+
ToolParams.model_json_schema() # camelCase, no title/default noise
|
|
240
210
|
```
|
|
241
211
|
|
|
242
212
|
### Runtime — build flat request before HTTP call
|
|
243
213
|
|
|
244
214
|
```python
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
body = merge_config_and_invocation(config, llm_invocation_dict)
|
|
215
|
+
request = google_config.merge(llm_invocation_dict, query="EU AI Act")
|
|
216
|
+
body = GoogleConfig.provider_query_params(request) # upstream provider dict
|
|
248
217
|
```
|
|
249
218
|
|
|
250
219
|
### Shared types and errors
|
|
@@ -263,9 +232,9 @@ from unique_search_proxy_core import (
|
|
|
263
232
|
## 7. Features summary
|
|
264
233
|
|
|
265
234
|
- Discriminated provider configs (`engine`, `crawler` Literal discriminators)
|
|
266
|
-
- **Search-only:** `ExposableParam` policy
|
|
267
|
-
- **Agent:**
|
|
268
|
-
- **Crawl:**
|
|
235
|
+
- **Search-only:** `ExposableParam` policy; config-owned `request_model` / `exposed_params_model` / `merge` / `provider_query_params`
|
|
236
|
+
- **Agent:** `BingAgentConfig.request_model()` (injects `query`; excludes `output_schema`)
|
|
237
|
+
- **Crawl:** `BasicConfig.request_model()` (injects `urls`); `merge_crawler_config_and_invocation`
|
|
269
238
|
- CamelCase JSON aliases on all models
|
|
270
239
|
- Zero server dependencies (import-linter enforced in the client package)
|
|
271
240
|
|
{unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/README.md
RENAMED
|
@@ -32,17 +32,15 @@ flowchart TB
|
|
|
32
32
|
|
|
33
33
|
subgraph core["unique_search_proxy_core"]
|
|
34
34
|
Contracts["Response & error models"]
|
|
35
|
-
Config["*Config deployment models"]
|
|
36
|
-
Project["Schema projection & merge"]
|
|
35
|
+
Config["*Config deployment models\n(request_model / exposed_params_model / merge)"]
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
AC --> Config
|
|
40
|
-
AC --> Project
|
|
41
39
|
Client --> Contracts
|
|
42
40
|
Client --> Config
|
|
43
41
|
SDK --> Contracts
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
Config -->|"flat request body"| SDK
|
|
43
|
+
Config -->|"flat request body"| Client
|
|
46
44
|
```
|
|
47
45
|
|
|
48
46
|
System overview → [../README.md](../README.md)
|
|
@@ -51,81 +49,63 @@ System overview → [../README.md](../README.md)
|
|
|
51
49
|
|
|
52
50
|
## 3. Key concepts
|
|
53
51
|
|
|
54
|
-
|
|
52
|
+
**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.
|
|
55
53
|
|
|
56
|
-
### 3.1
|
|
54
|
+
### 3.1 Config-owned API (search engines)
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```mermaid
|
|
65
|
-
flowchart TB
|
|
66
|
-
subgraph search["Search engines only"]
|
|
67
|
-
GC["GoogleConfig\n(ExposableParam knobs)"]
|
|
68
|
-
Proj["projection.py\nbuild_request_model\nbuild_llm_call_model"]
|
|
69
|
-
GSR["GoogleSearchRequest"]
|
|
70
|
-
LLM["LLM call schema"]
|
|
71
|
-
GC --> Proj
|
|
72
|
-
Proj --> GSR
|
|
73
|
-
Proj --> LLM
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
subgraph agent["Agent engines"]
|
|
77
|
-
BC["BingAgentConfig\n(plain fields)"]
|
|
78
|
-
AProj["agent_engines/projection.py\nbuild_agent_request_model"]
|
|
79
|
-
BSR["BingAgentSearchRequest"]
|
|
80
|
-
BC --> AProj
|
|
81
|
-
AProj -->|"via model_derivation"| BSR
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
subgraph crawl["Crawlers"]
|
|
85
|
-
BCrawl["BasicConfig\n(no urls)"]
|
|
86
|
-
CProj["crawlers/projection.py\nbuild_crawl_request_model"]
|
|
87
|
-
BCR["BasicCrawlRequest\n(urls injected)"]
|
|
88
|
-
BCrawl --> CProj
|
|
89
|
-
CProj -->|"via model_derivation"| BCR
|
|
90
|
-
end
|
|
56
|
+
```
|
|
57
|
+
Admin JSON → GoogleConfig {expose, value}
|
|
58
|
+
├─ GoogleConfig.request_model() → GoogleSearchRequest (HTTP body, query required)
|
|
59
|
+
├─ config.exposed_params_model() → GoogleExposedParams (LLM knobs; tool inherits it)
|
|
60
|
+
├─ config.merge(llm_args, query=…) → validated GoogleSearchRequest
|
|
61
|
+
└─ GoogleConfig.provider_query_params(req) → upstream provider dict
|
|
91
62
|
```
|
|
92
63
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
|
98
|
-
|
|
99
|
-
| **Deployment config** | Admin / deployment UI | `{ "engine": "google", "gl": { "expose": true, "value": "de" }, … }` |
|
|
100
|
-
| **LLM call schema** | Tool manifest shown to the model | `{ "query", "gl" }` — only fields where `expose: true` |
|
|
101
|
-
| **HTTP request body** | `POST /v1/search` wire format | `{ "engine": "google", "query": "…", "gl": "de", "fetchSize": 10 }` |
|
|
64
|
+
| Method | Kind | Returns |
|
|
65
|
+
|--------|------|---------|
|
|
66
|
+
| `request_model()` (classmethod, cached) | search / agent / crawl | `SearchRequestBase` (required `query`) or `CrawlRequestBase` (required `urls`) + config fields; `ExposableParam` knobs unwrapped to optional plain types |
|
|
67
|
+
| `exposed_params_model()` (instance) | search only | `ExposedParams` subclass with exactly the `expose=True` knobs (camelCase aliases, description-only schema), or `None` |
|
|
68
|
+
| `merge(overrides, *, query)` (instance) | search only | deployment defaults + LLM overrides + query → validated `request_model()` instance |
|
|
69
|
+
| `provider_query_params(request)` (classmethod) | search only | request serialized for the upstream provider, minus `_provider_param_exclude_fields` (Google adds `search_engine_id`) |
|
|
102
70
|
|
|
103
|
-
|
|
71
|
+
Agent engines (`BingAgentConfig`, …) and crawlers (`BasicConfig`, …) only implement `request_model()`; crawlers additionally keep `merge_crawler_config_and_invocation`.
|
|
104
72
|
|
|
105
|
-
### 3.
|
|
73
|
+
### 3.2 ExposableParam — search-engine only
|
|
106
74
|
|
|
107
75
|
Optional **search** parameters use `ExposableParam[T]`:
|
|
108
76
|
|
|
109
77
|
- **`value`** — admin default merged into every request (`null` = deactivated)
|
|
110
|
-
- **`expose`** — when `true`, the parameter appears on the LLM
|
|
78
|
+
- **`expose`** — when `true`, the parameter appears on the LLM-facing exposed-params model
|
|
111
79
|
|
|
112
80
|
```python
|
|
113
81
|
gl: ExposableParam[str | None] = ExposableParam(expose=False, value="de") # admin-fixed
|
|
114
82
|
gl: ExposableParam[str | None] = ExposableParam(expose=True, value=None) # LLM-overridable
|
|
115
83
|
```
|
|
116
84
|
|
|
117
|
-
|
|
85
|
+
Bare scalars are **not** coerced — deployment JSON must use the explicit `{"expose": …, "value": …}` shape.
|
|
86
|
+
|
|
87
|
+
### 3.3 ExposedParams — the LLM tool-schema contract
|
|
118
88
|
|
|
119
|
-
|
|
89
|
+
`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:
|
|
120
90
|
|
|
121
91
|
```python
|
|
122
|
-
|
|
92
|
+
Exposed = config.exposed_params_model() # GoogleExposedParams | None
|
|
93
|
+
class ToolParams(ToolParamsBase, Exposed): ... # or create_model(__base__=(...))
|
|
94
|
+
|
|
95
|
+
ToolParams.model_json_schema() # camelCase knobs, no title/default noise
|
|
96
|
+
Exposed.model_fields # the exposed field names
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
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.
|
|
123
100
|
|
|
124
|
-
|
|
101
|
+
### 3.4 merge — deployment defaults + LLM overrides
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
request = google_config.merge({"gl": "de"}, query="EU AI Act")
|
|
125
105
|
# → validated GoogleSearchRequest ready for POST /v1/search
|
|
126
106
|
```
|
|
127
107
|
|
|
128
|
-
The proxy receives a flat body; it does not resolve deployment config over HTTP.
|
|
108
|
+
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.
|
|
129
109
|
|
|
130
110
|
### 3.5 merge_crawler_config_and_invocation — crawler only
|
|
131
111
|
|
|
@@ -145,25 +125,16 @@ flowchart TB
|
|
|
145
125
|
subgraph core_pkg["unique_search_proxy_core"]
|
|
146
126
|
Schema["schema.py"]
|
|
147
127
|
Errors["errors.py"]
|
|
148
|
-
|
|
149
|
-
PP["param_policy/"]
|
|
150
|
-
Proj["projection.py\n(search + LLM projection)"]
|
|
151
|
-
AProj["agent_engines/projection.py"]
|
|
152
|
-
CProj["crawlers/projection.py"]
|
|
128
|
+
PP["param_policy/\nExposableParam · ExposedParams\nrequest bases · derive"]
|
|
153
129
|
Prov["providers/schema.py"]
|
|
154
130
|
SE["search_engines/"]
|
|
155
131
|
AE["agent_engines/"]
|
|
156
132
|
CR["crawlers/"]
|
|
157
133
|
end
|
|
158
134
|
|
|
159
|
-
PP --> Proj
|
|
160
135
|
PP --> SE
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
MD --> CProj
|
|
164
|
-
Proj --> SE
|
|
165
|
-
AProj --> AE
|
|
166
|
-
CProj --> CR
|
|
136
|
+
PP --> AE
|
|
137
|
+
PP --> CR
|
|
167
138
|
Prov --> SE
|
|
168
139
|
Prov --> CR
|
|
169
140
|
SE --> Schema
|
|
@@ -176,15 +147,15 @@ flowchart TB
|
|
|
176
147
|
|--------|----------------|
|
|
177
148
|
| `schema.py` | Shared API models: `SearchResponse`, `AgentSearchResponse`, `CrawlResponse`, `WebSearchResult`, `ErrorResponse`, SSE events |
|
|
178
149
|
| `errors.py` | `ProxyError` hierarchy and stable `ProxyErrorCode` enum |
|
|
179
|
-
| `
|
|
180
|
-
| `param_policy
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
150
|
+
| `param_policy/exposable_param.py` | `ExposableParam` value object, factory-default merge, type introspection, OpenAPI naming |
|
|
151
|
+
| `param_policy/exposed_params.py` | `ExposedParams` base for LLM-facing parameter models (schema noise stripping) |
|
|
152
|
+
| `param_policy/request_base.py` | `SearchRequestBase` / `AgentRequestBase` / `CrawlRequestBase` (required leading fields) |
|
|
153
|
+
| `param_policy/annotations.py` | Annotation unwrapping helpers (private, used by `derive`) |
|
|
154
|
+
| `param_policy/derive.py` | `derive_request_model` / `derive_exposed_params_model` factories called by the config base classes |
|
|
184
155
|
| `providers/schema.py` | JSON Schema + defaults for deployment UIs (`provider_config_json_schema`, …) |
|
|
185
|
-
| `search_engines/` | Config models
|
|
186
|
-
| `agent_engines/` | Agent config/request models, output schema |
|
|
187
|
-
| `crawlers/` | `*Config` deployment models + derived `*CrawlRequest`
|
|
156
|
+
| `search_engines/` | Config models with the config-owned API (`request_model` / `exposed_params_model` / `merge` / `provider_query_params`), request union |
|
|
157
|
+
| `agent_engines/` | Agent config/request models (`request_model`), output schema |
|
|
158
|
+
| `crawlers/` | `*Config` deployment models + derived `*CrawlRequest` bodies, `merge_crawler_config_and_invocation` |
|
|
188
159
|
|
|
189
160
|
---
|
|
190
161
|
|
|
@@ -216,21 +187,19 @@ schema = provider_config_json_schema("search_engine", "google")
|
|
|
216
187
|
defaults = provider_default_config("search_engine", "google")
|
|
217
188
|
```
|
|
218
189
|
|
|
219
|
-
### Tool manifest — LLM
|
|
190
|
+
### Tool manifest — exposed LLM knobs
|
|
220
191
|
|
|
221
192
|
```python
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
# descriptor.call_schema → JSON Schema for the LLM tool
|
|
193
|
+
Exposed = google_config.exposed_params_model() # GoogleExposedParams | None
|
|
194
|
+
class ToolParams(ToolParamsBase, Exposed): ... # graft knobs by inheritance
|
|
195
|
+
ToolParams.model_json_schema() # camelCase, no title/default noise
|
|
226
196
|
```
|
|
227
197
|
|
|
228
198
|
### Runtime — build flat request before HTTP call
|
|
229
199
|
|
|
230
200
|
```python
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
body = merge_config_and_invocation(config, llm_invocation_dict)
|
|
201
|
+
request = google_config.merge(llm_invocation_dict, query="EU AI Act")
|
|
202
|
+
body = GoogleConfig.provider_query_params(request) # upstream provider dict
|
|
234
203
|
```
|
|
235
204
|
|
|
236
205
|
### Shared types and errors
|
|
@@ -249,9 +218,9 @@ from unique_search_proxy_core import (
|
|
|
249
218
|
## 7. Features summary
|
|
250
219
|
|
|
251
220
|
- Discriminated provider configs (`engine`, `crawler` Literal discriminators)
|
|
252
|
-
- **Search-only:** `ExposableParam` policy
|
|
253
|
-
- **Agent:**
|
|
254
|
-
- **Crawl:**
|
|
221
|
+
- **Search-only:** `ExposableParam` policy; config-owned `request_model` / `exposed_params_model` / `merge` / `provider_query_params`
|
|
222
|
+
- **Agent:** `BingAgentConfig.request_model()` (injects `query`; excludes `output_schema`)
|
|
223
|
+
- **Crawl:** `BasicConfig.request_model()` (injects `urls`); `merge_crawler_config_and_invocation`
|
|
255
224
|
- CamelCase JSON aliases on all models
|
|
256
225
|
- Zero server dependencies (import-linter enforced in the client package)
|
|
257
226
|
|
{unique_search_proxy_core-2026.30.0.dev0 → unique_search_proxy_core-2026.30.0.dev2}/pyproject.toml
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique-search-proxy-core"
|
|
3
|
-
version = "2026.30.0.
|
|
3
|
+
version = "2026.30.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.30.0.
|
|
13
|
+
"unique-toolkit[monitoring]>=2026.30.0.dev10,<2026.30.0rc0",
|
|
14
14
|
|
|
15
15
|
]
|
|
16
16
|
|
|
@@ -2,13 +2,15 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from enum import StrEnum
|
|
5
|
-
from typing import TYPE_CHECKING, Annotated, AsyncIterator, Generic, TypeVar
|
|
5
|
+
from typing import TYPE_CHECKING, Annotated, AsyncIterator, ClassVar, Generic, TypeVar
|
|
6
6
|
|
|
7
7
|
from pydantic import BaseModel, Field
|
|
8
8
|
from pydantic.json_schema import SkipJsonSchema
|
|
9
9
|
from unique_toolkit._common.pydantic.rjsf_tags import RJSFMetaTag
|
|
10
10
|
|
|
11
11
|
from unique_search_proxy_core.agent_engines.output_schema import AgentSearchOutput
|
|
12
|
+
from unique_search_proxy_core.param_policy.derive import derive_request_model
|
|
13
|
+
from unique_search_proxy_core.param_policy.request_base import AgentRequestBase
|
|
12
14
|
from unique_search_proxy_core.schema import (
|
|
13
15
|
AgentSearchResponse,
|
|
14
16
|
AgentSearchStreamEvent,
|
|
@@ -42,11 +44,34 @@ class AgentEngineType(StrEnum):
|
|
|
42
44
|
VERTEXAI = "vertexai"
|
|
43
45
|
|
|
44
46
|
|
|
47
|
+
#: Config fields not accepted on the agent-search request body.
|
|
48
|
+
_AGENT_REQUEST_EXCLUDED_FIELDS = frozenset({"output_schema"})
|
|
49
|
+
|
|
50
|
+
|
|
45
51
|
class BaseAgentEngineConfig(BaseModel, Generic[T]):
|
|
46
52
|
"""Shared agent-engine config; each engine narrows ``engine`` with a Literal."""
|
|
47
53
|
|
|
48
54
|
model_config = camelized_model_config
|
|
49
55
|
|
|
56
|
+
#: Name of the derived request model; set by every concrete agent config.
|
|
57
|
+
_request_model_name: ClassVar[str]
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def request_model(cls) -> type[BaseModel]:
|
|
61
|
+
"""HTTP request body model, cached per config class.
|
|
62
|
+
|
|
63
|
+
:class:`AgentRequestBase` (required ``query``) + this config's fields,
|
|
64
|
+
excluding ``output_schema`` (server-side concern, not a request knob).
|
|
65
|
+
|
|
66
|
+
Example: ``BingAgentConfig.request_model()`` -> ``BingAgentSearchRequest``.
|
|
67
|
+
"""
|
|
68
|
+
return derive_request_model(
|
|
69
|
+
cls,
|
|
70
|
+
base=AgentRequestBase,
|
|
71
|
+
name=cls._request_model_name,
|
|
72
|
+
exclude=_AGENT_REQUEST_EXCLUDED_FIELDS,
|
|
73
|
+
)
|
|
74
|
+
|
|
50
75
|
engine: T
|
|
51
76
|
generation_instructions: Annotated[
|
|
52
77
|
str,
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from typing import Annotated, Literal
|
|
3
|
+
from typing import Annotated, ClassVar, Literal
|
|
4
4
|
|
|
5
|
-
from pydantic import
|
|
5
|
+
from pydantic import Field
|
|
6
6
|
from unique_toolkit._common.pydantic.rjsf_tags import RJSFMetaTag
|
|
7
7
|
|
|
8
8
|
from unique_search_proxy_core.agent_engines.base import (
|
|
9
9
|
AgentEngineType,
|
|
10
10
|
BaseAgentEngineConfig,
|
|
11
11
|
)
|
|
12
|
-
from unique_search_proxy_core.agent_engines.projection import build_agent_request_model
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class BingAgentConfig(BaseAgentEngineConfig[Literal[AgentEngineType.BING]]):
|
|
16
15
|
"""Deployment + request defaults for Bing grounding via Azure AI Projects."""
|
|
17
16
|
|
|
17
|
+
_request_model_name: ClassVar[str] = "BingAgentSearchRequest"
|
|
18
|
+
|
|
18
19
|
engine: Annotated[
|
|
19
20
|
Literal[AgentEngineType.BING], RJSFMetaTag.SpecialWidget.hidden()
|
|
20
21
|
] = Field(
|
|
@@ -37,11 +38,7 @@ class BingAgentConfig(BaseAgentEngineConfig[Literal[AgentEngineType.BING]]):
|
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
return build_agent_request_model(BingAgentConfig)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
BingAgentSearchRequest = bing_agent_request_model()
|
|
41
|
+
BingAgentSearchRequest = BingAgentConfig.request_model()
|
|
45
42
|
|
|
46
43
|
|
|
47
|
-
__all__ = ["BingAgentConfig", "BingAgentSearchRequest"
|
|
44
|
+
__all__ = ["BingAgentConfig", "BingAgentSearchRequest"]
|
|
@@ -11,7 +11,6 @@ from unique_search_proxy_core.agent_engines.base import (
|
|
|
11
11
|
BaseAgentEngineConfig,
|
|
12
12
|
)
|
|
13
13
|
from unique_search_proxy_core.agent_engines.bing.schema import BingAgentConfig
|
|
14
|
-
from unique_search_proxy_core.agent_engines.projection import build_agent_request_model
|
|
15
14
|
from unique_search_proxy_core.agent_engines.vertexai.schema import VertexAIAgentConfig
|
|
16
15
|
|
|
17
16
|
AgentEngineConfigTypes: TypeAlias = BingAgentConfig | VertexAIAgentConfig
|
|
@@ -48,17 +47,15 @@ def get_agent_engine_config_types_from_names(
|
|
|
48
47
|
|
|
49
48
|
|
|
50
49
|
def _union_members_from_mapping(
|
|
51
|
-
mapping: Mapping[str, type[
|
|
52
|
-
) -> tuple[type[
|
|
50
|
+
mapping: Mapping[str, type[BaseAgentEngineConfig]],
|
|
51
|
+
) -> tuple[type[BaseAgentEngineConfig], ...]:
|
|
53
52
|
return tuple(mapping.values())
|
|
54
53
|
|
|
55
54
|
|
|
56
55
|
def build_agent_search_request_union() -> Any:
|
|
57
56
|
"""Discriminated union of flat ``POST /v1/agent-search`` bodies."""
|
|
58
57
|
members = _union_members_from_mapping(ENGINE_NAME_TO_CONFIG)
|
|
59
|
-
request_models = tuple(
|
|
60
|
-
build_agent_request_model(config_cls) for config_cls in members
|
|
61
|
-
)
|
|
58
|
+
request_models = tuple(config_cls.request_model() for config_cls in members)
|
|
62
59
|
if len(request_models) == 1:
|
|
63
60
|
return request_models[0]
|
|
64
61
|
return Annotated[
|