Skip to main content

openai_compat/types/assistants/
params.rs

1//! Assistants (beta v2) request parameter types.
2//!
3//! Scalars are typed; deeply polymorphic fields use [`serde_json::Value`].
4
5use serde::Serialize;
6use serde_json::Value;
7
8// ---------------------------------------------------------------------------
9// List query parameters (shared across the beta list endpoints)
10// ---------------------------------------------------------------------------
11
12/// Query parameters for the beta cursor-paginated list endpoints.
13///
14/// Not every field applies to every endpoint (`run_id` is messages-only,
15/// `include` is steps-only); unused fields are simply left unset (DRY).
16#[derive(Debug, Clone, Default)]
17pub struct ListParams {
18    pub after: Option<String>,
19    pub before: Option<String>,
20    pub limit: Option<u32>,
21    pub order: Option<String>,
22    pub run_id: Option<String>,
23    pub include: Option<Vec<String>>,
24}
25
26impl ListParams {
27    pub fn new() -> Self {
28        Self::default()
29    }
30
31    pub fn after(mut self, after: impl Into<String>) -> Self {
32        self.after = Some(after.into());
33        self
34    }
35
36    pub fn before(mut self, before: impl Into<String>) -> Self {
37        self.before = Some(before.into());
38        self
39    }
40
41    pub fn limit(mut self, limit: u32) -> Self {
42        self.limit = Some(limit);
43        self
44    }
45
46    /// Sort order: `"asc"` or `"desc"`.
47    pub fn order(mut self, order: impl Into<String>) -> Self {
48        self.order = Some(order.into());
49        self
50    }
51
52    /// Filter messages by originating run (messages list only).
53    pub fn run_id(mut self, run_id: impl Into<String>) -> Self {
54        self.run_id = Some(run_id.into());
55        self
56    }
57
58    /// Extra fields to include in the response (run steps list only).
59    pub fn include(mut self, include: Vec<String>) -> Self {
60        self.include = Some(include);
61        self
62    }
63
64    pub(crate) fn to_query(&self) -> Vec<(String, String)> {
65        let mut query = crate::pagination::cursor_query(
66            self.after.as_deref(),
67            self.before.as_deref(),
68            self.limit,
69            self.order.as_deref(),
70        );
71        if let Some(run_id) = &self.run_id {
72            query.push(("run_id".into(), run_id.clone()));
73        }
74        if let Some(include) = &self.include {
75            for item in include {
76                query.push(("include[]".into(), item.clone()));
77            }
78        }
79        query
80    }
81}
82
83// ---------------------------------------------------------------------------
84// Assistant params
85// ---------------------------------------------------------------------------
86
87/// Request body for `POST /assistants`.
88#[derive(Debug, Clone, Serialize, Default)]
89pub struct AssistantCreateParams {
90    pub model: String,
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub name: Option<String>,
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub description: Option<String>,
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub instructions: Option<String>,
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub metadata: Option<std::collections::HashMap<String, String>>,
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub temperature: Option<f64>,
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub top_p: Option<f64>,
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub reasoning_effort: Option<String>,
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub response_format: Option<Value>,
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub tools: Option<Vec<Value>>,
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub tool_resources: Option<Value>,
111}
112
113impl AssistantCreateParams {
114    pub fn new(model: impl Into<String>) -> Self {
115        Self {
116            model: model.into(),
117            ..Self::default()
118        }
119    }
120
121    pub fn name(mut self, name: impl Into<String>) -> Self {
122        self.name = Some(name.into());
123        self
124    }
125
126    pub fn description(mut self, description: impl Into<String>) -> Self {
127        self.description = Some(description.into());
128        self
129    }
130
131    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
132        self.instructions = Some(instructions.into());
133        self
134    }
135
136    pub fn metadata(mut self, metadata: std::collections::HashMap<String, String>) -> Self {
137        self.metadata = Some(metadata);
138        self
139    }
140
141    pub fn temperature(mut self, temperature: f64) -> Self {
142        self.temperature = Some(temperature);
143        self
144    }
145
146    pub fn top_p(mut self, top_p: f64) -> Self {
147        self.top_p = Some(top_p);
148        self
149    }
150
151    pub fn reasoning_effort(mut self, effort: impl Into<String>) -> Self {
152        self.reasoning_effort = Some(effort.into());
153        self
154    }
155
156    pub fn response_format(mut self, response_format: Value) -> Self {
157        self.response_format = Some(response_format);
158        self
159    }
160
161    pub fn tools(mut self, tools: Vec<Value>) -> Self {
162        self.tools = Some(tools);
163        self
164    }
165
166    pub fn tool_resources(mut self, tool_resources: Value) -> Self {
167        self.tool_resources = Some(tool_resources);
168        self
169    }
170}
171
172/// Request body for `POST /assistants/{id}` (update). All fields optional.
173#[derive(Debug, Clone, Serialize, Default)]
174pub struct AssistantUpdateParams {
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub model: Option<String>,
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub name: Option<String>,
179    #[serde(skip_serializing_if = "Option::is_none")]
180    pub description: Option<String>,
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub instructions: Option<String>,
183    #[serde(skip_serializing_if = "Option::is_none")]
184    pub metadata: Option<std::collections::HashMap<String, String>>,
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub temperature: Option<f64>,
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub top_p: Option<f64>,
189    #[serde(skip_serializing_if = "Option::is_none")]
190    pub reasoning_effort: Option<String>,
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub response_format: Option<Value>,
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub tools: Option<Vec<Value>>,
195    #[serde(skip_serializing_if = "Option::is_none")]
196    pub tool_resources: Option<Value>,
197}
198
199impl AssistantUpdateParams {
200    pub fn new() -> Self {
201        Self::default()
202    }
203
204    pub fn model(mut self, model: impl Into<String>) -> Self {
205        self.model = Some(model.into());
206        self
207    }
208
209    pub fn name(mut self, name: impl Into<String>) -> Self {
210        self.name = Some(name.into());
211        self
212    }
213
214    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
215        self.instructions = Some(instructions.into());
216        self
217    }
218
219    pub fn metadata(mut self, metadata: std::collections::HashMap<String, String>) -> Self {
220        self.metadata = Some(metadata);
221        self
222    }
223
224    pub fn tools(mut self, tools: Vec<Value>) -> Self {
225        self.tools = Some(tools);
226        self
227    }
228
229    pub fn tool_resources(mut self, tool_resources: Value) -> Self {
230        self.tool_resources = Some(tool_resources);
231        self
232    }
233
234    pub fn description(mut self, description: impl Into<String>) -> Self {
235        self.description = Some(description.into());
236        self
237    }
238
239    pub fn temperature(mut self, temperature: f64) -> Self {
240        self.temperature = Some(temperature);
241        self
242    }
243
244    pub fn top_p(mut self, top_p: f64) -> Self {
245        self.top_p = Some(top_p);
246        self
247    }
248
249    pub fn reasoning_effort(mut self, effort: impl Into<String>) -> Self {
250        self.reasoning_effort = Some(effort.into());
251        self
252    }
253
254    pub fn response_format(mut self, response_format: Value) -> Self {
255        self.response_format = Some(response_format);
256        self
257    }
258}
259
260// ---------------------------------------------------------------------------
261// Thread params
262// ---------------------------------------------------------------------------
263
264/// Request body for `POST /threads`.
265#[derive(Debug, Clone, Serialize, Default)]
266pub struct ThreadCreateParams {
267    #[serde(skip_serializing_if = "Option::is_none")]
268    pub messages: Option<Vec<Value>>,
269    #[serde(skip_serializing_if = "Option::is_none")]
270    pub metadata: Option<std::collections::HashMap<String, String>>,
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub tool_resources: Option<Value>,
273}
274
275impl ThreadCreateParams {
276    pub fn new() -> Self {
277        Self::default()
278    }
279
280    pub fn messages(mut self, messages: Vec<Value>) -> Self {
281        self.messages = Some(messages);
282        self
283    }
284
285    pub fn metadata(mut self, metadata: std::collections::HashMap<String, String>) -> Self {
286        self.metadata = Some(metadata);
287        self
288    }
289
290    pub fn tool_resources(mut self, tool_resources: Value) -> Self {
291        self.tool_resources = Some(tool_resources);
292        self
293    }
294}
295
296/// Request body for `POST /threads/{id}` (update).
297#[derive(Debug, Clone, Serialize, Default)]
298pub struct ThreadUpdateParams {
299    #[serde(skip_serializing_if = "Option::is_none")]
300    pub metadata: Option<std::collections::HashMap<String, String>>,
301    #[serde(skip_serializing_if = "Option::is_none")]
302    pub tool_resources: Option<Value>,
303}
304
305impl ThreadUpdateParams {
306    pub fn new() -> Self {
307        Self::default()
308    }
309
310    pub fn metadata(mut self, metadata: std::collections::HashMap<String, String>) -> Self {
311        self.metadata = Some(metadata);
312        self
313    }
314
315    pub fn tool_resources(mut self, tool_resources: Value) -> Self {
316        self.tool_resources = Some(tool_resources);
317        self
318    }
319}
320
321// ---------------------------------------------------------------------------
322// Message params
323// ---------------------------------------------------------------------------
324
325/// Message content on create: a plain string or a list of content blocks
326/// (kept as [`serde_json::Value`] for the polymorphic block shapes).
327#[derive(Debug, Clone, Serialize)]
328#[serde(untagged)]
329pub enum MessageContentInput {
330    Text(String),
331    Blocks(Vec<Value>),
332}
333
334impl From<&str> for MessageContentInput {
335    fn from(text: &str) -> Self {
336        Self::Text(text.to_string())
337    }
338}
339
340impl From<String> for MessageContentInput {
341    fn from(text: String) -> Self {
342        Self::Text(text)
343    }
344}
345
346impl From<Vec<Value>> for MessageContentInput {
347    fn from(blocks: Vec<Value>) -> Self {
348        Self::Blocks(blocks)
349    }
350}
351
352/// Request body for `POST /threads/{tid}/messages`.
353#[derive(Debug, Clone, Serialize)]
354pub struct MessageCreateParams {
355    /// `"user"` or `"assistant"`.
356    pub role: String,
357    pub content: MessageContentInput,
358    #[serde(skip_serializing_if = "Option::is_none")]
359    pub attachments: Option<Vec<Value>>,
360    #[serde(skip_serializing_if = "Option::is_none")]
361    pub metadata: Option<std::collections::HashMap<String, String>>,
362}
363
364impl MessageCreateParams {
365    pub fn new(role: impl Into<String>, content: impl Into<MessageContentInput>) -> Self {
366        Self {
367            role: role.into(),
368            content: content.into(),
369            attachments: None,
370            metadata: None,
371        }
372    }
373
374    /// A message with role `"user"`.
375    pub fn user(content: impl Into<MessageContentInput>) -> Self {
376        Self::new("user", content)
377    }
378
379    /// A message with role `"assistant"`.
380    pub fn assistant(content: impl Into<MessageContentInput>) -> Self {
381        Self::new("assistant", content)
382    }
383
384    pub fn attachments(mut self, attachments: Vec<Value>) -> Self {
385        self.attachments = Some(attachments);
386        self
387    }
388
389    pub fn metadata(mut self, metadata: std::collections::HashMap<String, String>) -> Self {
390        self.metadata = Some(metadata);
391        self
392    }
393}
394
395/// Request body for `POST /threads/{tid}/messages/{mid}` (update).
396#[derive(Debug, Clone, Serialize, Default)]
397pub struct MessageUpdateParams {
398    #[serde(skip_serializing_if = "Option::is_none")]
399    pub metadata: Option<std::collections::HashMap<String, String>>,
400}
401
402impl MessageUpdateParams {
403    pub fn new() -> Self {
404        Self::default()
405    }
406
407    pub fn metadata(mut self, metadata: std::collections::HashMap<String, String>) -> Self {
408        self.metadata = Some(metadata);
409        self
410    }
411}
412
413// ---------------------------------------------------------------------------
414// Run params
415// ---------------------------------------------------------------------------
416
417/// Request body for `POST /threads/{tid}/runs`.
418#[derive(Debug, Clone, Serialize, Default)]
419pub struct RunCreateParams {
420    pub assistant_id: String,
421    #[serde(skip_serializing_if = "Option::is_none")]
422    pub model: Option<String>,
423    #[serde(skip_serializing_if = "Option::is_none")]
424    pub instructions: Option<String>,
425    #[serde(skip_serializing_if = "Option::is_none")]
426    pub additional_instructions: Option<String>,
427    #[serde(skip_serializing_if = "Option::is_none")]
428    pub additional_messages: Option<Vec<Value>>,
429    #[serde(skip_serializing_if = "Option::is_none")]
430    pub metadata: Option<std::collections::HashMap<String, String>>,
431    #[serde(skip_serializing_if = "Option::is_none")]
432    pub temperature: Option<f64>,
433    #[serde(skip_serializing_if = "Option::is_none")]
434    pub top_p: Option<f64>,
435    #[serde(skip_serializing_if = "Option::is_none")]
436    pub max_completion_tokens: Option<i64>,
437    #[serde(skip_serializing_if = "Option::is_none")]
438    pub max_prompt_tokens: Option<i64>,
439    #[serde(skip_serializing_if = "Option::is_none")]
440    pub parallel_tool_calls: Option<bool>,
441    #[serde(skip_serializing_if = "Option::is_none")]
442    pub reasoning_effort: Option<String>,
443    #[serde(skip_serializing_if = "Option::is_none")]
444    pub response_format: Option<Value>,
445    #[serde(skip_serializing_if = "Option::is_none")]
446    pub tool_choice: Option<Value>,
447    #[serde(skip_serializing_if = "Option::is_none")]
448    pub tools: Option<Vec<Value>>,
449    #[serde(skip_serializing_if = "Option::is_none")]
450    pub truncation_strategy: Option<Value>,
451}
452
453impl RunCreateParams {
454    pub fn new(assistant_id: impl Into<String>) -> Self {
455        Self {
456            assistant_id: assistant_id.into(),
457            ..Self::default()
458        }
459    }
460
461    pub fn model(mut self, model: impl Into<String>) -> Self {
462        self.model = Some(model.into());
463        self
464    }
465
466    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
467        self.instructions = Some(instructions.into());
468        self
469    }
470
471    pub fn additional_instructions(mut self, instructions: impl Into<String>) -> Self {
472        self.additional_instructions = Some(instructions.into());
473        self
474    }
475
476    pub fn additional_messages(mut self, messages: Vec<Value>) -> Self {
477        self.additional_messages = Some(messages);
478        self
479    }
480
481    pub fn metadata(mut self, metadata: std::collections::HashMap<String, String>) -> Self {
482        self.metadata = Some(metadata);
483        self
484    }
485
486    pub fn temperature(mut self, temperature: f64) -> Self {
487        self.temperature = Some(temperature);
488        self
489    }
490
491    pub fn top_p(mut self, top_p: f64) -> Self {
492        self.top_p = Some(top_p);
493        self
494    }
495
496    pub fn max_completion_tokens(mut self, max: i64) -> Self {
497        self.max_completion_tokens = Some(max);
498        self
499    }
500
501    pub fn max_prompt_tokens(mut self, max: i64) -> Self {
502        self.max_prompt_tokens = Some(max);
503        self
504    }
505
506    pub fn parallel_tool_calls(mut self, parallel: bool) -> Self {
507        self.parallel_tool_calls = Some(parallel);
508        self
509    }
510
511    pub fn reasoning_effort(mut self, effort: impl Into<String>) -> Self {
512        self.reasoning_effort = Some(effort.into());
513        self
514    }
515
516    pub fn response_format(mut self, response_format: Value) -> Self {
517        self.response_format = Some(response_format);
518        self
519    }
520
521    pub fn tool_choice(mut self, tool_choice: Value) -> Self {
522        self.tool_choice = Some(tool_choice);
523        self
524    }
525
526    pub fn tools(mut self, tools: Vec<Value>) -> Self {
527        self.tools = Some(tools);
528        self
529    }
530
531    pub fn truncation_strategy(mut self, strategy: Value) -> Self {
532        self.truncation_strategy = Some(strategy);
533        self
534    }
535}
536
537/// Request body for `POST /threads/{tid}/runs/{rid}` (update).
538#[derive(Debug, Clone, Serialize, Default)]
539pub struct RunUpdateParams {
540    #[serde(skip_serializing_if = "Option::is_none")]
541    pub metadata: Option<std::collections::HashMap<String, String>>,
542}
543
544impl RunUpdateParams {
545    pub fn new() -> Self {
546        Self::default()
547    }
548
549    pub fn metadata(mut self, metadata: std::collections::HashMap<String, String>) -> Self {
550        self.metadata = Some(metadata);
551        self
552    }
553}
554
555/// A single tool output submitted to a run awaiting action.
556#[derive(Debug, Clone, Serialize)]
557pub struct ToolOutput {
558    pub tool_call_id: String,
559    pub output: String,
560}
561
562impl ToolOutput {
563    pub fn new(tool_call_id: impl Into<String>, output: impl Into<String>) -> Self {
564        Self {
565            tool_call_id: tool_call_id.into(),
566            output: output.into(),
567        }
568    }
569}
570
571/// Request body for `POST /threads/{tid}/runs/{rid}/submit_tool_outputs`.
572#[derive(Debug, Clone, Serialize)]
573pub struct SubmitToolOutputsParams {
574    pub tool_outputs: Vec<ToolOutput>,
575}
576
577impl SubmitToolOutputsParams {
578    pub fn new(tool_outputs: Vec<ToolOutput>) -> Self {
579        Self { tool_outputs }
580    }
581}