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