Skip to main content

gproxy_protocol/openai/
models.rs

1use serde::{Deserialize, Serialize};
2
3use super::common::{ListObjectType, ModelObjectType, OpenAiModelId, Rest};
4
5pub type ModelsWireModel = super::common::OpenAiWireModel<ListModelsRequest, ModelListResponse>;
6pub type ModelRetrieveWireModel = super::common::OpenAiWireModel<RetrieveModelRequest, Model>;
7
8#[derive(
9    Debug, Clone, PartialEq, Serialize, Deserialize, Default, gproxy_protocol_macros::WireBuilder,
10)]
11#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
12pub struct ListModelsRequest {
13    #[serde(default, flatten)]
14    pub rest: Rest,
15}
16
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
18#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
19pub struct RetrieveModelRequest {
20    pub model: OpenAiModelId,
21    #[serde(default, flatten)]
22    pub rest: Rest,
23}
24
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
26#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
27pub struct ModelListResponse {
28    pub data: Vec<Model>,
29    pub object: ListObjectType,
30    #[serde(default, flatten)]
31    pub rest: Rest,
32}
33
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
35#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
36pub struct Model {
37    pub id: OpenAiModelId,
38    #[serde(default, skip_serializing_if = "Option::is_none")]
39    pub created: Option<u64>,
40    // gproxy extensions: limits and capabilities surfaced from providers that
41    // report them (Claude, Gemini, Codex). The official OpenAI model object
42    // has none of these fields, so a consumer of this schema must treat them
43    // as gproxy-specific rather than OpenAI-compatible.
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub display_name: Option<String>,
46    /// Input allowance. OpenAI has no separate input limit — the context
47    /// window *is* the accepted input size — so peers that split the two
48    /// (Claude's `max_input_tokens`, Gemini's `inputTokenLimit`) map here.
49    #[serde(default, skip_serializing_if = "Option::is_none")]
50    pub context_window: Option<u64>,
51    /// Codex reports an override ceiling separately from the default budget;
52    /// kept verbatim so a client can see the headroom, while `context_window`
53    /// carries the value the catalogue consumes.
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub max_context_window: Option<u64>,
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub max_output_tokens: Option<u64>,
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub thinking_supported: Option<bool>,
60    pub object: ModelObjectType,
61    // Optional because OpenAI-compatible providers (DeepSeek among them)
62    // omit it; decoding a model list must not fail on their behalf.
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub owned_by: Option<String>,
65    #[serde(default, flatten)]
66    pub rest: Rest,
67}