1use crate::error::TypeError;
2use crate::SettingsType;
3use potato_util::json_to_pydict;
4use potato_util::{pyobject_to_json, PyHelperFuncs, UtilError};
5use pyo3::prelude::*;
6use pyo3::types::PyDict;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::collections::HashMap;
10
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12#[pyclass]
13pub struct AudioParam {
14 #[pyo3(get, set)]
15 pub format: String,
16 #[pyo3(get, set)]
17 pub voice: String,
18}
19
20#[pymethods]
21impl AudioParam {
22 #[new]
23 pub fn new(format: String, voice: String) -> Self {
24 AudioParam { format, voice }
25 }
26
27 pub fn model_dump<'py>(&self, py: Python<'py>) -> Result<Bound<'py, PyDict>, TypeError> {
28 let pydict = PyDict::new(py);
30 pydict.set_item("format", &self.format)?;
31 pydict.set_item("voice", &self.voice)?;
32 Ok(pydict)
33 }
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
37#[pyclass]
38pub struct ContentPart {
39 #[pyo3(get, set)]
40 pub r#type: String,
41 #[pyo3(get, set)]
42 pub text: String,
43}
44
45#[pymethods]
46impl ContentPart {
47 #[new]
48 pub fn new(r#type: String, text: String) -> Self {
49 ContentPart { r#type, text }
50 }
51
52 pub fn model_dump<'py>(&self, py: Python<'py>) -> Result<Bound<'py, PyDict>, TypeError> {
53 let pydict = PyDict::new(py);
55
56 pydict.set_item("type", &self.r#type)?;
57 pydict.set_item("text", &self.text)?;
58 Ok(pydict)
59 }
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
63#[serde(untagged)]
64#[pyclass]
65pub enum Content {
66 Text(String),
67 Array(Vec<ContentPart>),
68}
69
70#[pymethods]
71impl Content {
72 #[new]
73 #[pyo3(signature = (text=None, parts=None))]
74 pub fn new(text: Option<String>, parts: Option<Vec<ContentPart>>) -> Result<Self, TypeError> {
75 match (text, parts) {
76 (Some(t), None) => Ok(Content::Text(t)),
77 (None, Some(p)) => Ok(Content::Array(p)),
78 _ => Err(TypeError::InvalidInput(
79 "Either text or parts must be provided, but not both.".to_string(),
80 )),
81 }
82 }
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
86#[pyclass]
87pub struct Prediction {
88 #[pyo3(get, set)]
89 pub r#type: String,
90 #[pyo3(get, set)]
91 pub content: Content,
92}
93
94#[pymethods]
95impl Prediction {
96 #[new]
97 pub fn new(r#type: String, content: Content) -> Self {
98 Prediction { r#type, content }
99 }
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
103#[pyclass]
104pub struct StreamOptions {
105 #[pyo3(get, set)]
106 pub include_obfuscation: Option<bool>,
107 #[pyo3(get, set)]
108 pub include_usage: Option<bool>,
109}
110
111#[pymethods]
112impl StreamOptions {
113 #[new]
114 pub fn new(include_obfuscation: Option<bool>, include_usage: Option<bool>) -> Self {
115 StreamOptions {
116 include_obfuscation,
117 include_usage,
118 }
119 }
120}
121
122#[pyclass]
123#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
124#[serde(rename_all = "lowercase")]
125pub enum ToolChoiceMode {
126 #[serde(rename = "none")]
127 NA,
128 Auto,
129 Required,
130}
131
132#[pymethods]
133impl ToolChoiceMode {
134 fn __str__(&self) -> String {
135 PyHelperFuncs::__str__(self)
136 }
137}
138
139#[pyclass]
141#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
142pub struct FunctionChoice {
143 #[pyo3(get, set)]
144 pub name: String,
145}
146
147#[pymethods]
148impl FunctionChoice {
149 #[new]
150 #[pyo3(signature = (name))]
151 pub fn new(name: String) -> Self {
152 Self { name }
153 }
154
155 fn __str__(&self) -> String {
156 PyHelperFuncs::__str__(self)
157 }
158}
159
160#[pyclass]
162#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
163pub struct FunctionToolChoice {
164 #[pyo3(get)]
165 pub r#type: String,
166 #[pyo3(get, set)]
167 pub function: FunctionChoice,
168}
169
170#[pymethods]
171impl FunctionToolChoice {
172 #[new]
173 #[pyo3(signature = (function))]
174 pub fn new(function: FunctionChoice) -> Self {
175 Self {
176 r#type: "function".to_string(),
177 function,
178 }
179 }
180
181 fn __str__(&self) -> String {
182 PyHelperFuncs::__str__(self)
183 }
184}
185
186#[pyclass]
188#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
189pub struct CustomChoice {
190 #[pyo3(get, set)]
191 pub name: String,
192}
193
194#[pymethods]
195impl CustomChoice {
196 #[new]
197 #[pyo3(signature = (name))]
198 pub fn new(name: String) -> Self {
199 Self { name }
200 }
201
202 fn __str__(&self) -> String {
203 PyHelperFuncs::__str__(self)
204 }
205}
206
207#[pyclass]
209#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
210pub struct CustomToolChoice {
211 #[pyo3(get)]
212 pub r#type: String,
213 #[pyo3(get, set)]
214 pub custom: CustomChoice,
215}
216
217#[pymethods]
218impl CustomToolChoice {
219 #[new]
220 #[pyo3(signature = (custom))]
221 pub fn new(custom: CustomChoice) -> Self {
222 Self {
223 r#type: "custom".to_string(),
224 custom,
225 }
226 }
227
228 fn __str__(&self) -> String {
229 PyHelperFuncs::__str__(self)
230 }
231}
232
233#[pyclass]
234#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
235pub struct ToolDefinition {
236 #[pyo3(get)]
237 pub r#type: String,
238 #[pyo3(get, set)]
239 pub function: FunctionChoice,
240}
241
242#[pymethods]
243impl ToolDefinition {
244 #[new]
245 #[pyo3(signature = (function_name))]
246 pub fn new(function_name: String) -> Self {
247 Self {
248 r#type: "function".to_string(),
249 function: FunctionChoice::new(function_name),
250 }
251 }
252
253 fn __str__(&self) -> String {
254 PyHelperFuncs::__str__(self)
255 }
256}
257
258#[pyclass]
260#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
261#[serde(rename_all = "lowercase")]
262pub enum AllowedToolsMode {
263 Auto,
265 Required,
267}
268
269#[pymethods]
270impl AllowedToolsMode {
271 fn __str__(&self) -> String {
272 PyHelperFuncs::__str__(self)
273 }
274}
275
276#[pyclass]
277#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
278pub struct InnerAllowedTools {
279 #[pyo3(get)]
280 pub mode: AllowedToolsMode,
281 #[pyo3(get)]
282 pub tools: Vec<ToolDefinition>,
283}
284
285#[pyclass]
286#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
287pub struct AllowedTools {
288 #[pyo3(get)]
289 pub r#type: String,
290 #[pyo3(get)]
291 pub allowed_tools: InnerAllowedTools,
292}
293
294#[pymethods]
295impl AllowedTools {
296 #[new]
297 #[pyo3(signature = (mode, tools))]
298 pub fn new(mode: AllowedToolsMode, tools: Vec<ToolDefinition>) -> Self {
299 Self {
300 r#type: "allowed_tools".to_string(),
301 allowed_tools: InnerAllowedTools { mode, tools },
302 }
303 }
304
305 #[staticmethod]
307 #[pyo3(signature = (mode, function_names))]
308 pub fn from_function_names(mode: AllowedToolsMode, function_names: Vec<String>) -> Self {
309 let tools = function_names
310 .into_iter()
311 .map(ToolDefinition::new)
312 .collect();
313
314 Self::new(mode, tools)
315 }
316
317 fn __str__(&self) -> String {
318 PyHelperFuncs::__str__(self)
319 }
320}
321
322#[pyclass]
324#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
325#[serde(untagged)]
326pub enum ToolChoice {
327 Mode(ToolChoiceMode),
329 Function(FunctionToolChoice),
331 Custom(CustomToolChoice),
333 Allowed(AllowedTools),
335}
336
337#[pymethods]
338impl ToolChoice {
339 #[staticmethod]
341 #[pyo3(signature = (mode))]
342 pub fn from_mode(mode: &ToolChoiceMode) -> Self {
343 ToolChoice::Mode(mode.clone())
344 }
345
346 #[staticmethod]
348 #[pyo3(signature = (function_name))]
349 pub fn from_function(function_name: String) -> Self {
350 ToolChoice::Function(FunctionToolChoice::new(FunctionChoice::new(function_name)))
351 }
352
353 #[staticmethod]
355 #[pyo3(signature = (custom_name))]
356 pub fn from_custom(custom_name: String) -> Self {
357 ToolChoice::Custom(CustomToolChoice::new(CustomChoice::new(custom_name)))
358 }
359
360 #[staticmethod]
362 #[pyo3(signature = (allowed_tools))]
363 pub fn from_allowed_tools(allowed_tools: AllowedTools) -> Self {
364 ToolChoice::Allowed(allowed_tools)
365 }
366
367 fn __str__(&self) -> String {
368 PyHelperFuncs::__str__(self)
369 }
370}
371
372impl Default for ToolChoice {
373 fn default() -> Self {
374 ToolChoice::Mode(ToolChoiceMode::Auto)
375 }
376}
377
378#[pyclass]
379#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
380pub struct FunctionDefinition {
381 #[pyo3(get, set)]
382 pub name: String,
383
384 #[pyo3(get, set)]
385 #[serde(skip_serializing_if = "Option::is_none")]
386 pub description: Option<String>,
387
388 #[serde(skip_serializing_if = "Option::is_none")]
389 pub parameters: Option<Value>,
390
391 #[pyo3(get, set)]
392 #[serde(skip_serializing_if = "Option::is_none")]
393 pub strict: Option<bool>,
394}
395
396#[pymethods]
397impl FunctionDefinition {
398 #[new]
399 #[pyo3(signature = (name, description=None, parameters=None, strict=None))]
400 pub fn new(
401 name: String,
402 description: Option<String>,
403 parameters: Option<&Bound<'_, PyAny>>,
404 strict: Option<bool>,
405 ) -> Result<Self, UtilError> {
406 let params = match parameters {
407 Some(obj) => Some(pyobject_to_json(obj)?),
408 None => None,
409 };
410
411 Ok(Self {
412 name,
413 description,
414 parameters: params,
415 strict,
416 })
417 }
418
419 fn __str__(&self) -> String {
420 PyHelperFuncs::__str__(self)
421 }
422}
423
424#[pyclass]
425#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
426pub struct FunctionTool {
427 #[pyo3(get, set)]
428 pub function: FunctionDefinition,
429
430 #[pyo3(get, set)]
431 pub r#type: String,
432}
433
434#[pymethods]
435impl FunctionTool {
436 #[new]
437 #[pyo3(signature = (function, r#type))]
438 pub fn new(function: FunctionDefinition, r#type: String) -> Self {
439 FunctionTool { function, r#type }
440 }
441}
442
443#[pyclass]
444#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
445pub struct TextFormat {
446 #[pyo3(get, set)]
447 pub r#type: String,
448}
449
450#[pymethods]
451impl TextFormat {
452 #[new]
453 #[pyo3(signature = (r#type))]
454 pub fn new(r#type: String) -> Self {
455 TextFormat { r#type }
456 }
457}
458
459#[pyclass]
460#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
461pub struct Grammar {
462 #[pyo3(get, set)]
464 pub definition: String,
465
466 #[pyo3(get, set)]
468 pub syntax: String,
469}
470
471#[pymethods]
472impl Grammar {
473 #[new]
474 #[pyo3(signature = (definition, syntax))]
475 pub fn new(definition: String, syntax: String) -> Self {
476 Self { definition, syntax }
477 }
478
479 fn __str__(&self) -> String {
480 PyHelperFuncs::__str__(self)
481 }
482}
483
484#[pyclass]
485#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
486pub struct GrammarFormat {
487 #[pyo3(get, set)]
488 pub grammar: Grammar,
489 #[pyo3(get, set)]
490 pub r#type: String,
491}
492
493#[pymethods]
494impl GrammarFormat {
495 #[new]
496 #[pyo3(signature = (grammar, r#type))]
497 pub fn new(grammar: Grammar, r#type: String) -> Self {
498 Self { grammar, r#type }
499 }
500}
501
502#[pyclass]
503#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
504#[serde(untagged)]
505pub enum CustomToolFormat {
506 Text(TextFormat),
508 Grammar(GrammarFormat),
510}
511
512#[pymethods]
513impl CustomToolFormat {
514 #[new]
515 #[pyo3(signature = (r#type=None, grammar=None))]
516 pub fn new(r#type: Option<String>, grammar: Option<Grammar>) -> Self {
517 match (r#type, grammar) {
518 (Some(r#type), None) => CustomToolFormat::Text(TextFormat::new(r#type)),
519 (None, Some(grammar)) => {
520 CustomToolFormat::Grammar(GrammarFormat::new(grammar, String::new()))
521 }
522 _ => CustomToolFormat::Text(TextFormat::new(String::new())),
523 }
524 }
525}
526
527#[pyclass]
528#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
529pub struct CustomDefinition {
530 #[pyo3(get, set)]
531 pub name: String,
532
533 #[pyo3(get, set)]
534 #[serde(skip_serializing_if = "Option::is_none")]
535 pub description: Option<String>,
536
537 #[pyo3(get, set)]
538 #[serde(skip_serializing_if = "Option::is_none")]
539 pub format: Option<CustomToolFormat>,
540}
541
542#[pymethods]
543impl CustomDefinition {
544 #[new]
545 #[pyo3(signature = (name, description=None, format=None))]
546 pub fn new(
547 name: String,
548 description: Option<String>,
549 format: Option<CustomToolFormat>,
550 ) -> Self {
551 Self {
552 name,
553 description,
554 format,
555 }
556 }
557}
558
559#[pyclass]
560#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
561pub struct CustomTool {
562 #[pyo3(get, set)]
563 pub custom: CustomDefinition,
564
565 #[pyo3(get, set)]
566 pub r#type: String,
567}
568
569#[pymethods]
570impl CustomTool {
571 #[new]
572 #[pyo3(signature = (custom, r#type))]
573 pub fn new(custom: CustomDefinition, r#type: String) -> Self {
574 CustomTool { custom, r#type }
575 }
576}
577
578#[pyclass]
579#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
580#[serde(untagged)]
581pub enum Tool {
582 Function(FunctionTool),
583
584 Custom(CustomTool),
585}
586
587#[pymethods]
588impl Tool {
589 #[new]
590 #[pyo3(signature = (function=None, custom=None))]
591 pub fn new(
592 function: Option<FunctionTool>,
593 custom: Option<CustomTool>,
594 ) -> Result<Self, TypeError> {
595 match (function, custom) {
596 (Some(function), None) => Ok(Tool::Function(function)),
597 (None, Some(custom)) => Ok(Tool::Custom(custom)),
598 _ => Err(TypeError::InvalidInput("Invalid tool definition".into())),
599 }
600 }
601}
602
603#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
604#[pyclass]
605pub struct OpenAIChatSettings {
606 #[pyo3(get, set)]
607 #[serde(skip_serializing_if = "Option::is_none")]
608 pub max_completion_tokens: Option<usize>,
609
610 #[pyo3(get, set)]
611 #[serde(skip_serializing_if = "Option::is_none")]
612 pub temperature: Option<f32>,
613
614 #[pyo3(get, set)]
615 #[serde(skip_serializing_if = "Option::is_none")]
616 pub top_p: Option<f32>,
617
618 #[pyo3(get, set)]
619 #[serde(skip_serializing_if = "Option::is_none")]
620 pub top_k: Option<i32>,
621
622 #[pyo3(get, set)]
623 #[serde(skip_serializing_if = "Option::is_none")]
624 pub frequency_penalty: Option<f32>,
625
626 #[pyo3(get, set)]
627 #[serde(skip_serializing_if = "Option::is_none")]
628 pub timeout: Option<f32>,
629
630 #[pyo3(get, set)]
631 #[serde(skip_serializing_if = "Option::is_none")]
632 pub parallel_tool_calls: Option<bool>,
633
634 #[pyo3(get, set)]
635 #[serde(skip_serializing_if = "Option::is_none")]
636 pub seed: Option<u64>,
637
638 #[pyo3(get, set)]
639 #[serde(skip_serializing_if = "Option::is_none")]
640 pub logit_bias: Option<HashMap<String, i32>>,
641
642 #[pyo3(get, set)]
643 #[serde(skip_serializing_if = "Option::is_none")]
644 pub stop_sequences: Option<Vec<String>>,
645
646 #[pyo3(get, set)]
647 #[serde(skip_serializing_if = "Option::is_none")]
648 pub logprobs: Option<bool>,
649
650 #[pyo3(get, set)]
651 #[serde(skip_serializing_if = "Option::is_none")]
652 pub audio: Option<AudioParam>,
653
654 #[pyo3(get, set)]
655 #[serde(skip_serializing_if = "Option::is_none")]
656 pub metadata: Option<HashMap<String, String>>,
657
658 #[pyo3(get, set)]
659 #[serde(skip_serializing_if = "Option::is_none")]
660 pub modalities: Option<Vec<String>>,
661
662 #[pyo3(get, set)]
663 #[serde(skip_serializing_if = "Option::is_none")]
664 pub n: Option<usize>,
665
666 #[pyo3(get, set)]
667 #[serde(skip_serializing_if = "Option::is_none")]
668 pub prediction: Option<Prediction>,
669
670 #[pyo3(get, set)]
671 #[serde(skip_serializing_if = "Option::is_none")]
672 pub presence_penalty: Option<f32>,
673
674 #[pyo3(get, set)]
675 #[serde(skip_serializing_if = "Option::is_none")]
676 pub prompt_cache_key: Option<String>,
677
678 #[pyo3(get, set)]
679 #[serde(skip_serializing_if = "Option::is_none")]
680 pub reasoning_effort: Option<String>,
681
682 #[pyo3(get, set)]
683 #[serde(skip_serializing_if = "Option::is_none")]
684 pub safety_identifier: Option<String>,
685
686 #[pyo3(get, set)]
687 #[serde(skip_serializing_if = "Option::is_none")]
688 pub service_tier: Option<String>,
689
690 #[pyo3(get, set)]
691 #[serde(skip_serializing_if = "Option::is_none")]
692 pub store: Option<bool>,
693
694 #[pyo3(get, set)]
695 #[serde(skip_serializing_if = "Option::is_none")]
696 pub stream: Option<bool>,
697
698 #[pyo3(get, set)]
699 #[serde(skip_serializing_if = "Option::is_none")]
700 pub stream_options: Option<StreamOptions>,
701
702 #[pyo3(get, set)]
703 #[serde(skip_serializing_if = "Option::is_none")]
704 pub tool_choice: Option<ToolChoice>,
705
706 #[pyo3(get, set)]
707 #[serde(skip_serializing_if = "Option::is_none")]
708 pub tools: Option<Vec<Tool>>,
709
710 #[pyo3(get, set)]
711 #[serde(skip_serializing_if = "Option::is_none")]
712 pub top_logprobs: Option<i32>,
713
714 #[pyo3(get, set)]
715 #[serde(skip_serializing_if = "Option::is_none")]
716 pub verbosity: Option<String>,
717
718 #[serde(skip_serializing_if = "Option::is_none")]
720 pub extra_body: Option<Value>,
721}
722
723#[pymethods]
724impl OpenAIChatSettings {
725 #[new]
726 #[pyo3(signature = (max_completion_tokens=None, temperature=None, top_p=None, top_k=None, frequency_penalty=None, timeout=None, parallel_tool_calls=None, seed=None, logit_bias=None, stop_sequences=None, logprobs=None, audio=None, metadata=None, modalities=None, n=None, prediction=None, presence_penalty=None, prompt_cache_key=None, reasoning_effort=None, safety_identifier=None, service_tier=None, store=None, stream=None, stream_options=None, tool_choice=None, tools=None, top_logprobs=None, verbosity=None, extra_body=None))]
727 #[allow(clippy::too_many_arguments)]
728 pub fn new(
729 max_completion_tokens: Option<usize>,
730 temperature: Option<f32>,
731 top_p: Option<f32>,
732 top_k: Option<i32>,
733 frequency_penalty: Option<f32>,
734 timeout: Option<f32>,
735 parallel_tool_calls: Option<bool>,
736 seed: Option<u64>,
737 logit_bias: Option<HashMap<String, i32>>,
738 stop_sequences: Option<Vec<String>>,
739 logprobs: Option<bool>,
740 audio: Option<AudioParam>,
741 metadata: Option<HashMap<String, String>>,
742 modalities: Option<Vec<String>>,
743 n: Option<usize>,
744 prediction: Option<Prediction>,
745 presence_penalty: Option<f32>,
746 prompt_cache_key: Option<String>,
747 reasoning_effort: Option<String>,
748 safety_identifier: Option<String>,
749 service_tier: Option<String>,
750 store: Option<bool>,
751 stream: Option<bool>,
752 stream_options: Option<StreamOptions>,
753 tool_choice: Option<ToolChoice>,
754 tools: Option<Vec<Tool>>,
755 top_logprobs: Option<i32>,
756 verbosity: Option<String>,
757 extra_body: Option<&Bound<'_, PyAny>>,
758 ) -> Result<Self, UtilError> {
759 let extra = match extra_body {
760 Some(obj) => Some(pyobject_to_json(obj)?),
761 None => None,
762 };
763
764 Ok(OpenAIChatSettings {
765 max_completion_tokens,
766 temperature,
767 top_p,
768 top_k,
769 frequency_penalty,
770 timeout,
771 parallel_tool_calls,
772 seed,
773 logit_bias,
774 stop_sequences,
775 logprobs,
776 audio,
777 metadata,
778 modalities,
779 n,
780 prediction,
781 presence_penalty,
782 prompt_cache_key,
783 reasoning_effort,
784 safety_identifier,
785 service_tier,
786 store,
787 stream,
788 stream_options,
789 tool_choice,
790 tools,
791 top_logprobs,
792 verbosity,
793 extra_body: extra,
794 })
795 }
796
797 fn __str__(&self) -> String {
798 PyHelperFuncs::__str__(self)
799 }
800
801 #[getter]
802 pub fn extra_body<'py>(
803 &self,
804 py: Python<'py>,
805 ) -> Result<Option<Bound<'py, PyDict>>, TypeError> {
806 Ok(self
808 .extra_body
809 .as_ref()
810 .map(|v| {
811 let pydict = PyDict::new(py);
812 json_to_pydict(py, v, &pydict)
813 })
814 .transpose()?)
815 }
816
817 pub fn model_dump<'py>(&self, py: Python<'py>) -> Result<Bound<'py, PyDict>, TypeError> {
818 let json = serde_json::to_value(self)?;
820 let pydict = PyDict::new(py);
821 json_to_pydict(py, &json, &pydict)?;
822 Ok(pydict)
823 }
824
825 pub fn settings_type(&self) -> SettingsType {
826 SettingsType::OpenAIChat
827 }
828}