Skip to main content

gproxy_protocol/wire/openai/
rerank.rs

1//! OpenRouter `/rerank` and separately named DashScope `/reranks` wire shapes.
2//! Sources: openrouter/Submit a rerank request.md and dashscope/OpenAI-compatible Rerank.md.
3//! OpenRouter requires each result document; DashScope may omit it.
4use crate::{Rest, WireRequest, WireResponse};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
8#[serde(rename_all = "snake_case")]
9#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
10#[derive(gproxy_protocol_macros::DeclaredFields)]
11#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
12pub struct RerankRequestBody {
13    #[serde(
14        default,
15        deserialize_with = "present_nullable",
16        skip_serializing_if = "Option::is_none"
17    )]
18    pub provider: Option<Option<ProviderPreferences>>,
19    pub model: String,
20    pub query: String,
21    pub documents: Vec<RerankDocumentInput>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub top_n: Option<i64>,
24    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
25    pub rest: Rest,
26}
27pub type RerankRequest = WireRequest<RerankRequestBody>;
28#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29#[serde(untagged)]
30#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
31#[derive(gproxy_protocol_macros::DeclaredFields)]
32#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
33pub enum RerankDocumentInput {
34    Text(String),
35    Structured(RerankDocument),
36}
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
38#[serde(rename_all = "snake_case")]
39#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
40#[derive(gproxy_protocol_macros::DeclaredFields)]
41#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
42pub struct RerankDocument {
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub text: Option<String>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub image: Option<String>,
47    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
48    pub rest: Rest,
49}
50#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
51#[serde(rename_all = "snake_case")]
52#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
53#[derive(gproxy_protocol_macros::DeclaredFields)]
54#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
55pub struct RerankResponseBody {
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub id: Option<String>,
58    pub model: String,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub provider: Option<String>,
61    pub results: Vec<RerankResult>,
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub usage: Option<RerankUsage>,
64    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
65    pub rest: Rest,
66}
67pub type RerankResponse = WireResponse<RerankResponseBody>;
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
69#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
70#[derive(gproxy_protocol_macros::DeclaredFields)]
71#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
72pub enum RerankObject {
73    #[serde(rename = "list")]
74    List,
75}
76#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
77#[serde(rename_all = "snake_case")]
78#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
79#[derive(gproxy_protocol_macros::DeclaredFields)]
80#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
81pub struct RerankResult {
82    pub index: i64,
83    pub relevance_score: serde_json::Number,
84    pub document: RerankDocument,
85    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
86    pub rest: Rest,
87}
88#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
89#[serde(rename_all = "snake_case")]
90#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
91#[derive(gproxy_protocol_macros::DeclaredFields)]
92#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
93pub struct RerankUsage {
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub search_units: Option<i64>,
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub total_tokens: Option<i64>,
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub cost: Option<serde_json::Number>,
100    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
101    pub rest: Rest,
102}
103
104fn present_nullable<'de, D, T>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
105where
106    D: serde::Deserializer<'de>,
107    T: Deserialize<'de>,
108{
109    Option::<T>::deserialize(deserializer).map(Some)
110}
111
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
113#[serde(rename_all = "snake_case")]
114#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
115#[derive(gproxy_protocol_macros::DeclaredFields)]
116#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
117pub struct ProviderPreferences {
118    #[serde(
119        default,
120        deserialize_with = "present_nullable",
121        skip_serializing_if = "Option::is_none"
122    )]
123    pub allow_fallbacks: Option<Option<bool>>,
124    #[serde(
125        default,
126        deserialize_with = "present_nullable",
127        skip_serializing_if = "Option::is_none"
128    )]
129    pub data_collection: Option<Option<DataCollection>>,
130    #[serde(
131        default,
132        deserialize_with = "present_nullable",
133        skip_serializing_if = "Option::is_none"
134    )]
135    pub enforce_distillable_text: Option<Option<bool>>,
136    #[serde(
137        default,
138        deserialize_with = "present_nullable",
139        skip_serializing_if = "Option::is_none"
140    )]
141    pub ignore: Option<Option<Vec<String>>>,
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub max_price: Option<MaxPrice>,
144    #[serde(
145        default,
146        deserialize_with = "present_nullable",
147        skip_serializing_if = "Option::is_none"
148    )]
149    pub only: Option<Option<Vec<String>>>,
150    #[serde(
151        default,
152        deserialize_with = "present_nullable",
153        skip_serializing_if = "Option::is_none"
154    )]
155    pub order: Option<Option<Vec<String>>>,
156    #[serde(
157        default,
158        deserialize_with = "present_nullable",
159        skip_serializing_if = "Option::is_none"
160    )]
161    pub preferred_max_latency: Option<Option<PreferredCutoff>>,
162    #[serde(
163        default,
164        deserialize_with = "present_nullable",
165        skip_serializing_if = "Option::is_none"
166    )]
167    pub preferred_min_throughput: Option<Option<PreferredCutoff>>,
168    #[serde(
169        default,
170        deserialize_with = "present_nullable",
171        skip_serializing_if = "Option::is_none"
172    )]
173    pub quantizations: Option<Option<Vec<Quantization>>>,
174    #[serde(
175        default,
176        deserialize_with = "present_nullable",
177        skip_serializing_if = "Option::is_none"
178    )]
179    pub require_parameters: Option<Option<bool>>,
180    #[serde(
181        default,
182        deserialize_with = "present_nullable",
183        skip_serializing_if = "Option::is_none"
184    )]
185    pub sort: Option<Option<ProviderSort>>,
186    #[serde(
187        default,
188        deserialize_with = "present_nullable",
189        skip_serializing_if = "Option::is_none"
190    )]
191    pub zdr: Option<Option<bool>>,
192    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
193    pub rest: Rest,
194}
195
196#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
197#[serde(rename_all = "snake_case")]
198#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
199#[derive(gproxy_protocol_macros::DeclaredFields)]
200#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
201pub struct MaxPrice {
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub audio: Option<String>,
204    #[serde(skip_serializing_if = "Option::is_none")]
205    pub completion: Option<String>,
206    #[serde(skip_serializing_if = "Option::is_none")]
207    pub image: Option<String>,
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub prompt: Option<String>,
210    #[serde(skip_serializing_if = "Option::is_none")]
211    pub request: Option<String>,
212    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
213    pub rest: Rest,
214}
215
216#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
217#[serde(rename_all = "snake_case")]
218#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
219#[derive(gproxy_protocol_macros::DeclaredFields)]
220#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
221pub struct PercentileCutoffs {
222    #[serde(
223        default,
224        deserialize_with = "present_nullable",
225        skip_serializing_if = "Option::is_none"
226    )]
227    pub p50: Option<Option<serde_json::Number>>,
228    #[serde(
229        default,
230        deserialize_with = "present_nullable",
231        skip_serializing_if = "Option::is_none"
232    )]
233    pub p75: Option<Option<serde_json::Number>>,
234    #[serde(
235        default,
236        deserialize_with = "present_nullable",
237        skip_serializing_if = "Option::is_none"
238    )]
239    pub p90: Option<Option<serde_json::Number>>,
240    #[serde(
241        default,
242        deserialize_with = "present_nullable",
243        skip_serializing_if = "Option::is_none"
244    )]
245    pub p99: Option<Option<serde_json::Number>>,
246    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
247    pub rest: Rest,
248}
249
250#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
251#[serde(rename_all = "snake_case")]
252#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
253#[derive(gproxy_protocol_macros::DeclaredFields)]
254#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
255pub struct ProviderSortConfig {
256    #[serde(
257        default,
258        deserialize_with = "present_nullable",
259        skip_serializing_if = "Option::is_none"
260    )]
261    pub by: Option<Option<ProviderSortBy>>,
262    #[serde(
263        default,
264        deserialize_with = "present_nullable",
265        skip_serializing_if = "Option::is_none"
266    )]
267    pub partition: Option<Option<ProviderPartition>>,
268    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
269    pub rest: Rest,
270}
271
272#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
273#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
274#[derive(gproxy_protocol_macros::DeclaredFields)]
275#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
276pub enum DataCollection {
277    #[serde(rename = "deny")]
278    Deny,
279    #[serde(rename = "allow")]
280    Allow,
281}
282
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
284#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
285#[derive(gproxy_protocol_macros::DeclaredFields)]
286#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
287pub enum Quantization {
288    #[serde(rename = "int4")]
289    Int4,
290    #[serde(rename = "int8")]
291    Int8,
292    #[serde(rename = "fp4")]
293    Fp4,
294    #[serde(rename = "mxfp4")]
295    Mxfp4,
296    #[serde(rename = "nvfp4")]
297    Nvfp4,
298    #[serde(rename = "fp6")]
299    Fp6,
300    #[serde(rename = "fp8")]
301    Fp8,
302    #[serde(rename = "mxfp8")]
303    Mxfp8,
304    #[serde(rename = "fp16")]
305    Fp16,
306    #[serde(rename = "bf16")]
307    Bf16,
308    #[serde(rename = "fp32")]
309    Fp32,
310    #[serde(rename = "unknown")]
311    Unknown,
312}
313
314#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
315#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
316#[derive(gproxy_protocol_macros::DeclaredFields)]
317#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
318pub enum ProviderSortBy {
319    #[serde(rename = "price")]
320    Price,
321    #[serde(rename = "throughput")]
322    Throughput,
323    #[serde(rename = "latency")]
324    Latency,
325    #[serde(rename = "exacto")]
326    Exacto,
327}
328
329#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
330#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
331#[derive(gproxy_protocol_macros::DeclaredFields)]
332#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
333pub enum ProviderPartition {
334    #[serde(rename = "model")]
335    Model,
336    #[serde(rename = "none")]
337    None,
338}
339
340#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
341#[serde(untagged)]
342#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
343#[derive(gproxy_protocol_macros::DeclaredFields)]
344#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
345pub enum PreferredCutoff {
346    Number(serde_json::Number),
347    Percentiles(PercentileCutoffs),
348}
349
350#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
351#[serde(untagged)]
352#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
353#[derive(gproxy_protocol_macros::DeclaredFields)]
354#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
355pub enum ProviderSort {
356    By(ProviderSortBy),
357    Config(ProviderSortConfig),
358}
359
360/// DashScope's request accepts text documents and an optional ranking instruction.
361#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
362#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
363#[derive(gproxy_protocol_macros::DeclaredFields)]
364#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
365pub struct DashscopeRerankRequestBody {
366    /// Documented by DashScope under results.document: true returns input text.
367    #[serde(skip_serializing_if = "Option::is_none")]
368    pub return_documents: Option<bool>,
369    pub model: String,
370    pub query: String,
371    pub documents: Vec<String>,
372    #[serde(skip_serializing_if = "Option::is_none")]
373    pub top_n: Option<i64>,
374    #[serde(skip_serializing_if = "Option::is_none")]
375    pub instruct: Option<String>,
376    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
377    pub rest: Rest,
378}
379pub type DashscopeRerankRequest = WireRequest<DashscopeRerankRequestBody>;
380#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
381#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
382#[derive(gproxy_protocol_macros::DeclaredFields)]
383#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
384pub struct DashscopeRerankResponseBody {
385    pub id: String,
386    pub object: RerankObject,
387    pub model: String,
388    pub results: Vec<DashscopeRerankResult>,
389    pub usage: DashscopeRerankUsage,
390    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
391    pub rest: Rest,
392}
393pub type DashscopeRerankResponse = WireResponse<DashscopeRerankResponseBody>;
394#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
395#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
396#[derive(gproxy_protocol_macros::DeclaredFields)]
397#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
398pub struct DashscopeRerankResult {
399    pub index: i64,
400    pub relevance_score: serde_json::Number,
401    #[serde(skip_serializing_if = "Option::is_none")]
402    pub document: Option<DashscopeRerankDocument>,
403    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
404    pub rest: Rest,
405}
406#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
407#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
408#[derive(gproxy_protocol_macros::DeclaredFields)]
409#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
410pub struct DashscopeRerankDocument {
411    pub text: String,
412    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
413    pub rest: Rest,
414}
415#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
416#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
417#[derive(gproxy_protocol_macros::DeclaredFields)]
418#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
419pub struct DashscopeRerankUsage {
420    pub total_tokens: i64,
421    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
422    pub rest: Rest,
423}