Skip to main content

gproxy_protocol/wire/openai/
decisions.rs

1//! OpenAI Decisions API (public beta), verified against openai-python on 2026-10-08.
2//! `decision_create_params.py`, `decision.py`, and `decision_input_*_param.py`.
3//! Choice values distinguish booleans from strings; refusals are per question.
4use super::responses::ResponseUsage;
5use crate::{Rest, WireRequest, WireResponse};
6use serde::{Deserialize, Serialize};
7
8#[derive(
9    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
10)]
11#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
12#[derive(gproxy_protocol_macros::WireBuilder)]
13#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
14pub struct CreateDecisionRequestBody {
15    pub model: String,
16    pub input: DecisionInput,
17    pub questions: Vec<DecisionQuestion>,
18    #[serde(default, skip_serializing_if = "Option::is_none")]
19    pub safety_identifier: Option<String>,
20    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
21    pub rest: Rest,
22}
23
24#[derive(
25    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
26)]
27#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
28#[serde(untagged)]
29#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
30pub enum DecisionInput {
31    Text(String),
32    Messages(Vec<DecisionInputMessage>),
33}
34
35#[derive(
36    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
37)]
38#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
39#[derive(gproxy_protocol_macros::WireBuilder)]
40#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
41pub struct DecisionInputMessage {
42    pub role: DecisionRole,
43    #[serde(default, skip_serializing_if = "Option::is_none")]
44    #[serde(rename = "type")]
45    pub type_: Option<DecisionMessageType>,
46    pub content: DecisionContent,
47    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
48    pub rest: Rest,
49}
50
51#[derive(
52    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
53)]
54#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
55#[serde(rename_all = "snake_case")]
56#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
57pub enum DecisionRole {
58    User,
59}
60
61#[derive(
62    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
63)]
64#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
65#[serde(rename_all = "snake_case")]
66#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
67pub enum DecisionMessageType {
68    Message,
69}
70
71#[derive(
72    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
73)]
74#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
75#[serde(untagged)]
76#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
77pub enum DecisionContent {
78    Text(String),
79    Parts(Vec<DecisionInputPart>),
80}
81
82#[derive(
83    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
84)]
85#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
86#[serde(tag = "type", rename_all = "snake_case")]
87#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
88pub enum DecisionInputPart {
89    InputText {
90        text: String,
91        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
92        rest: Rest,
93    },
94    InputImage {
95        image_url: String,
96        #[serde(
97            default,
98            deserialize_with = "super::responses::input::present_nullable",
99            skip_serializing_if = "Option::is_none"
100        )]
101        detail: Option<Option<DecisionImageDetail>>,
102        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
103        rest: Rest,
104    },
105}
106
107#[derive(
108    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
109)]
110#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
111#[serde(rename_all = "snake_case")]
112#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
113pub enum DecisionImageDetail {
114    Low,
115    High,
116    Auto,
117    Original,
118}
119
120#[derive(
121    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
122)]
123#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
124#[serde(untagged)]
125#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
126pub enum DecisionChoiceValue {
127    String(String),
128    Boolean(bool),
129}
130
131#[derive(
132    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
133)]
134#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
135#[derive(gproxy_protocol_macros::WireBuilder)]
136#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
137pub struct DecisionChoice {
138    pub value: DecisionChoiceValue,
139    #[serde(default, skip_serializing_if = "Option::is_none")]
140    pub description: Option<String>,
141    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
142    pub rest: Rest,
143}
144
145#[derive(
146    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
147)]
148#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
149#[derive(gproxy_protocol_macros::WireBuilder)]
150#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
151pub struct DecisionScoreLevel {
152    pub label: String,
153    #[serde(default, skip_serializing_if = "Option::is_none")]
154    pub description: Option<String>,
155    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
156    pub rest: Rest,
157}
158
159#[derive(
160    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
161)]
162#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
163#[serde(tag = "type", rename_all = "snake_case")]
164#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
165pub enum DecisionQuestion {
166    Predicate {
167        #[serde(default, skip_serializing_if = "Option::is_none")]
168        name: Option<String>,
169        instructions: String,
170        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
171        rest: Rest,
172    },
173    Choice {
174        #[serde(default, skip_serializing_if = "Option::is_none")]
175        name: Option<String>,
176        instructions: String,
177        choices: Vec<DecisionChoice>,
178        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
179        rest: Rest,
180    },
181    Score {
182        #[serde(default, skip_serializing_if = "Option::is_none")]
183        name: Option<String>,
184        instructions: String,
185        levels: Vec<DecisionScoreLevel>,
186        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
187        rest: Rest,
188    },
189}
190
191#[derive(
192    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
193)]
194#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
195#[derive(gproxy_protocol_macros::WireBuilder)]
196#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
197pub struct CreateDecisionResponseBody {
198    pub model: String,
199    pub answers: Vec<DecisionAnswer>,
200    pub usage: ResponseUsage,
201    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
202    pub rest: Rest,
203}
204
205#[derive(
206    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
207)]
208#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
209#[derive(gproxy_protocol_macros::WireBuilder)]
210#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
211pub struct DecisionChoiceProbability {
212    pub value: DecisionChoiceValue,
213    pub probability: f64,
214    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
215    pub rest: Rest,
216}
217
218#[derive(
219    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
220)]
221#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
222#[derive(gproxy_protocol_macros::WireBuilder)]
223#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
224pub struct DecisionScoreProbability {
225    pub label: String,
226    pub value: i64,
227    pub probability: f64,
228    #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
229    pub rest: Rest,
230}
231
232#[derive(
233    Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::DeclaredFields,
234)]
235#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
236#[serde(tag = "type", rename_all = "snake_case")]
237#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
238pub enum DecisionAnswer {
239    Predicate {
240        #[serde(default, skip_serializing_if = "Option::is_none")]
241        name: Option<String>,
242        probability: f64,
243        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
244        rest: Rest,
245    },
246    Choice {
247        #[serde(default, skip_serializing_if = "Option::is_none")]
248        name: Option<String>,
249        choice: DecisionChoiceValue,
250        confidence: f64,
251        probabilities: Vec<DecisionChoiceProbability>,
252        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
253        rest: Rest,
254    },
255    Score {
256        #[serde(default, skip_serializing_if = "Option::is_none")]
257        name: Option<String>,
258        score: f64,
259        confidence: f64,
260        probabilities: Vec<DecisionScoreProbability>,
261        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
262        rest: Rest,
263    },
264    Refusal {
265        #[serde(default, skip_serializing_if = "Option::is_none")]
266        name: Option<String>,
267        #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
268        rest: Rest,
269    },
270}
271
272pub type CreateDecisionRequest = WireRequest<CreateDecisionRequestBody>;
273pub type CreateDecisionResponse = WireResponse<CreateDecisionResponseBody>;