1mod audio;
4mod batches;
5mod beta;
6mod chat;
7mod common;
8mod containers;
9mod conversations;
10mod core;
11mod evals;
12mod files;
13mod fine_tuning;
14mod images;
15mod longtail;
16mod responses;
17mod skills;
18mod uploads;
19mod vector_stores;
20mod videos;
21mod webhooks;
22
23use std::collections::BTreeMap;
24
25use serde::{Deserialize, Serialize};
26use serde_json::Value;
27
28use crate::Client;
29use crate::error::{Error, Result};
30#[cfg(feature = "tool-runner")]
31use crate::helpers::ToolDefinition;
32use crate::json_payload::JsonPayload;
33
34pub use beta::{
35 BetaAssistant, BetaAssistantTool, BetaRealtimeSession, BetaRealtimeTranscriptionSession,
36 BetaThread, BetaThreadMessage, BetaThreadMessageContent, BetaThreadRun,
37 BetaThreadRunIncompleteDetails, BetaThreadRunLastError, BetaThreadRunRequiredAction,
38 BetaThreadRunRequiredActionFunction, BetaThreadRunRequiredActionFunctionToolCall,
39 BetaThreadRunRequiredActionSubmitToolOutputs, BetaThreadRunStep, BetaThreadRunStepDetails,
40 BetaThreadRunTool, BetaThreadRunUsage, BetaThreadToolResources, ChatKitConfiguration,
41 ChatKitRateLimits, ChatKitSession, ChatKitThread, ChatKitThreadContent, ChatKitThreadItem,
42 ChatKitThreadStatus, ChatKitWorkflow,
43};
44#[cfg(feature = "structured-output")]
45pub use chat::ChatCompletionParseRequestBuilder;
46pub use chat::{
47 AssistantStreamRequestBuilder, ChatCompletionCreateRequestBuilder, ChatCompletionStoreMessage,
48 ChatCompletionStreamRequestBuilder,
49};
50#[cfg(feature = "tool-runner")]
51pub use chat::{
52 ChatCompletionRunToolsRequestBuilder, ChatCompletionRunner, ChatCompletionStreamingRunner,
53 ChatCompletionToolResult,
54};
55pub use common::{
56 BytesRequestBuilder, JsonRequestBuilder, ListRequestBuilder, NoContentRequestBuilder,
57};
58pub(crate) use common::{
59 TypedJsonRequestState, encode_path_segment, metadata_is_empty, value_from,
60};
61pub use core::{
62 Completion, CompletionChoice, CompletionLogProbs, CompletionUsage,
63 CompletionUsageCompletionTokensDetails, CompletionUsagePromptTokensDetails,
64 ModerationCreateResponse, ModerationResult,
65};
66pub use fine_tuning::{
67 GraderModel, GraderModelCatalog, GraderRunErrors, GraderRunMetadata, GraderRunResponse,
68 GraderValidateResponse,
69};
70pub use longtail::{
71 AudioSpeechCreateParams, AudioSpeechRequestBuilder, AudioTranscription,
72 AudioTranscriptionRequestBuilder, AudioTranscriptionSegment, AudioTranscriptionSegmentId,
73 AudioTranscriptionWord, AudioTranslation, AudioTranslationRequestBuilder, Batch,
74 BatchCreateParams, BatchCreateRequestBuilder, BatchError, BatchErrors, BatchRequestCounts,
75 BatchUsage, BatchUsageInputTokensDetails, BatchUsageOutputTokensDetails, Container,
76 ContainerCreateParams, ContainerExpiresAfter, ContainerFile, ContainerFileCreateParams,
77 Conversation, ConversationContentPart, ConversationCreateParams, ConversationInputItem,
78 ConversationItem, ConversationItemCreateParams, ConversationUpdateParams, Eval,
79 EvalCreateParams, EvalDataSourceConfig, EvalOutput, EvalOutputItem, EvalRun,
80 EvalRunCreateParams, EvalRunInput, EvalTestingCriterion, EvalUpdateParams,
81 FineTuningCheckpoint, FineTuningCheckpointPermission, FineTuningHyperparameterValue,
82 FineTuningJob, FineTuningJobCreateParams, FineTuningJobCreateRequestBuilder,
83 FineTuningJobError, FineTuningJobEvent, FineTuningJobHyperparameters, FineTuningJobIntegration,
84 FineTuningMetrics, FineTuningWandbIntegration, ImageData, ImageGenerateParams,
85 ImageGenerateRequestBuilder, ImageGenerationResponse, Skill, SkillCreateParams,
86 SkillUpdateParams, SkillVersion, SkillVersionContent, SkillVersionCreateParams, Video,
87 VideoCharacter, VideoCharacterCreateParams, VideoCreateParams,
88};
89#[cfg(feature = "realtime")]
90pub use responses::RealtimeSocketRequestBuilder;
91#[cfg(feature = "structured-output")]
92pub use responses::ResponseParseRequestBuilder;
93#[cfg(feature = "responses-ws")]
94pub use responses::ResponsesSocketRequestBuilder;
95pub use responses::{
96 RealtimeClientSecretCreateResponse, RealtimeSessionClientSecret, ResponseCreateRequestBuilder,
97 ResponseStreamRequestBuilder,
98};
99pub use uploads::UploadPart;
100pub use vector_stores::{
101 VectorStore, VectorStoreAttributeValue, VectorStoreAttributes, VectorStoreExpiresAfter,
102 VectorStoreFile, VectorStoreFileBatch, VectorStoreFileChunkingStrategy, VectorStoreFileContent,
103 VectorStoreFileCounts, VectorStoreFileLastError, VectorStoreMetadata, VectorStoreSearchContent,
104 VectorStoreSearchResponse, VectorStoreSearchResult, VectorStoreStaticFileChunkingStrategy,
105};
106
107macro_rules! json_payload_wrapper {
108 ($(#[$meta:meta])* $name:ident) => {
109 $(#[$meta])*
110 #[derive(Debug, Clone, Serialize, Deserialize)]
111 #[serde(transparent)]
112 pub struct $name(Value);
113
114 impl Default for $name {
115 fn default() -> Self {
116 Self(Value::Null)
117 }
118 }
119
120 impl From<Value> for $name {
121 fn from(value: Value) -> Self {
122 Self(value)
123 }
124 }
125
126 impl From<$name> for Value {
127 fn from(value: $name) -> Self {
128 value.0
129 }
130 }
131
132 impl $name {
133 pub fn as_raw(&self) -> &Value {
135 &self.0
136 }
137
138 pub fn into_raw(self) -> Value {
140 self.0
141 }
142
143 pub fn kind(&self) -> Option<&str> {
145 self.0.get("type").and_then(Value::as_str)
146 }
147 }
148 };
149}
150
151macro_rules! handle {
152 ($(#[$meta:meta])* $name:ident) => {
153 $(#[$meta])*
154 #[derive(Debug, Clone)]
155 pub struct $name {
156 client: Client,
157 }
158
159 impl $name {
160 pub(crate) fn new(client: Client) -> Self {
161 Self { client }
162 }
163 }
164 };
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize, Default)]
169pub struct DeleteResponse {
170 pub id: Option<String>,
172 #[serde(default)]
174 pub deleted: bool,
175 pub object: Option<String>,
177 #[serde(flatten)]
179 pub extra: BTreeMap<String, Value>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize, Default)]
184pub struct Model {
185 pub id: String,
187 #[serde(default)]
189 pub object: String,
190 pub owned_by: Option<String>,
192 #[serde(flatten)]
194 pub extra: BTreeMap<String, Value>,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize, Default)]
199pub struct FileObject {
200 pub id: String,
202 #[serde(default)]
204 pub object: String,
205 pub filename: Option<String>,
207 pub purpose: Option<String>,
209 pub bytes: Option<u64>,
211 #[serde(flatten)]
213 pub extra: BTreeMap<String, Value>,
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize, Default)]
218pub struct UploadObject {
219 pub id: String,
221 #[serde(default)]
223 pub object: String,
224 pub status: Option<String>,
226 #[serde(flatten)]
228 pub extra: BTreeMap<String, Value>,
229}
230
231#[derive(Debug, Clone, Serialize, Deserialize, Default)]
233pub struct EmbeddingResponse {
234 #[serde(default)]
236 pub object: String,
237 #[serde(default)]
239 pub data: Vec<EmbeddingData>,
240 pub usage: Option<EmbeddingUsage>,
242 #[serde(flatten)]
244 pub extra: BTreeMap<String, Value>,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize, Default)]
249pub struct EmbeddingData {
250 #[serde(default)]
252 pub embedding: Vec<f64>,
253 pub index: Option<u32>,
255 #[serde(default)]
257 pub object: String,
258 #[serde(flatten)]
260 pub extra: BTreeMap<String, Value>,
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize, Default)]
265pub struct EmbeddingUsage {
266 #[serde(default)]
268 pub prompt_tokens: u64,
269 #[serde(default)]
271 pub total_tokens: u64,
272 #[serde(flatten)]
274 pub extra: BTreeMap<String, Value>,
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize, Default)]
279pub struct InputTokenCount {
280 pub total_tokens: u64,
282 #[serde(flatten)]
284 pub extra: BTreeMap<String, Value>,
285}
286
287json_payload_wrapper!(
288 ChatCompletionStoreContentPart
290);
291json_payload_wrapper!(
292 ChatReasoningDetail
294);
295json_payload_wrapper!(
296 ChatToolChoice
298);
299json_payload_wrapper!(
300 ResponseInputPayload
302);
303json_payload_wrapper!(
304 ResponseInputItemPayload
306);
307json_payload_wrapper!(
308 RealtimeSessionPayload
310);
311json_payload_wrapper!(
312 ResponseOutputItemRaw
314);
315json_payload_wrapper!(
316 ResponseOutputContentPartRaw
318);
319
320#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
322#[serde(rename_all = "snake_case")]
323pub enum ChatToolChoiceMode {
324 None,
326 Auto,
328 Required,
330}
331
332impl From<ChatToolChoiceMode> for ChatToolChoice {
333 fn from(mode: ChatToolChoiceMode) -> Self {
334 let value = match mode {
335 ChatToolChoiceMode::None => Value::String("none".into()),
336 ChatToolChoiceMode::Auto => Value::String("auto".into()),
337 ChatToolChoiceMode::Required => Value::String("required".into()),
338 };
339 Self::from(value)
340 }
341}
342
343impl From<String> for ResponseInputPayload {
344 fn from(value: String) -> Self {
345 Self::from(Value::String(value))
346 }
347}
348
349impl From<&str> for ResponseInputPayload {
350 fn from(value: &str) -> Self {
351 Self::from(Value::String(value.into()))
352 }
353}
354
355impl From<Vec<ResponseInputItemPayload>> for ResponseInputPayload {
356 fn from(items: Vec<ResponseInputItemPayload>) -> Self {
357 Self::from(Value::Array(items.into_iter().map(Value::from).collect()))
358 }
359}
360
361impl ChatToolChoice {
362 pub fn none() -> Self {
364 ChatToolChoiceMode::None.into()
365 }
366
367 pub fn auto() -> Self {
369 ChatToolChoiceMode::Auto.into()
370 }
371
372 pub fn required() -> Self {
374 ChatToolChoiceMode::Required.into()
375 }
376
377 pub fn function(name: impl Into<String>) -> Self {
379 serde_json::json!({
380 "type": "function",
381 "function": {
382 "name": name.into(),
383 },
384 })
385 .into()
386 }
387
388 pub fn custom(name: impl Into<String>) -> Self {
390 serde_json::json!({
391 "type": "custom",
392 "custom": {
393 "name": name.into(),
394 },
395 })
396 .into()
397 }
398
399 pub fn mode_name(&self) -> Option<&str> {
401 self.0.as_str()
402 }
403}
404
405#[derive(Debug, Clone, Serialize, Deserialize, Default)]
407pub struct ChatCompletionFunctionCall {
408 pub name: String,
410 #[serde(default)]
412 pub arguments: String,
413}
414
415#[derive(Debug, Clone, Serialize, Deserialize, Default)]
417pub struct ChatCompletionToolCall {
418 pub id: String,
420 #[serde(rename = "type", default = "default_function_type")]
422 pub call_type: String,
423 pub function: ChatCompletionFunctionCall,
425 #[serde(flatten)]
427 pub extra: BTreeMap<String, Value>,
428}
429
430#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
432pub struct ChatCompletionTokenTopLogprob {
433 #[serde(default)]
435 pub token: String,
436 pub bytes: Option<Vec<u8>>,
438 #[serde(default)]
440 pub logprob: f64,
441 #[serde(flatten)]
443 pub extra: BTreeMap<String, Value>,
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
448pub struct ChatCompletionTokenLogprob {
449 #[serde(default)]
451 pub token: String,
452 pub bytes: Option<Vec<u8>>,
454 #[serde(default)]
456 pub logprob: f64,
457 #[serde(default)]
459 pub top_logprobs: Vec<ChatCompletionTokenTopLogprob>,
460 #[serde(flatten)]
462 pub extra: BTreeMap<String, Value>,
463}
464
465#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
467pub struct ChatCompletionChoiceLogprobs {
468 #[serde(default, skip_serializing_if = "Vec::is_empty")]
470 pub content: Vec<ChatCompletionTokenLogprob>,
471 #[serde(default, skip_serializing_if = "Vec::is_empty")]
473 pub refusal: Vec<ChatCompletionTokenLogprob>,
474 #[serde(flatten)]
476 pub extra: BTreeMap<String, Value>,
477}
478
479impl ChatCompletionChoiceLogprobs {
480 pub fn values(&self, field_name: &str) -> Option<&[ChatCompletionTokenLogprob]> {
482 match field_name {
483 "content" if !self.content.is_empty() => Some(&self.content),
484 "refusal" if !self.refusal.is_empty() => Some(&self.refusal),
485 _ => None,
486 }
487 }
488}
489
490#[derive(Debug, Clone, Serialize, Deserialize, Default)]
492pub struct ChatCompletionFunctionCallDelta {
493 pub name: Option<String>,
495 pub arguments: Option<String>,
497}
498
499#[derive(Debug, Clone, Serialize, Deserialize, Default)]
501pub struct ChatCompletionToolCallDelta {
502 pub index: Option<u32>,
504 pub id: Option<String>,
506 #[serde(rename = "type")]
508 pub call_type: Option<String>,
509 pub function: Option<ChatCompletionFunctionCallDelta>,
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize, Default)]
515pub struct ChatCompletionMessage {
516 pub role: String,
518 #[serde(skip_serializing_if = "Option::is_none")]
520 pub content: Option<String>,
521 #[serde(skip_serializing_if = "Option::is_none")]
523 pub name: Option<String>,
524 #[serde(skip_serializing_if = "Option::is_none")]
526 pub tool_call_id: Option<String>,
527 #[serde(default, skip_serializing_if = "Vec::is_empty")]
529 pub tool_calls: Vec<ChatCompletionToolCall>,
530 #[serde(skip_serializing_if = "Option::is_none")]
532 pub refusal: Option<String>,
533 #[serde(skip_serializing_if = "Option::is_none")]
535 pub reasoning_content: Option<String>,
536 #[serde(default, skip_serializing_if = "Vec::is_empty")]
538 pub reasoning_details: Vec<ChatReasoningDetail>,
539 #[serde(flatten)]
541 pub extra: BTreeMap<String, Value>,
542}
543
544impl ChatCompletionMessage {
545 pub fn system(content: impl Into<String>) -> Self {
547 Self {
548 role: "system".into(),
549 content: Some(content.into()),
550 ..Self::default()
551 }
552 }
553
554 pub fn user(content: impl Into<String>) -> Self {
556 Self {
557 role: "user".into(),
558 content: Some(content.into()),
559 ..Self::default()
560 }
561 }
562
563 pub fn assistant(content: impl Into<String>) -> Self {
565 Self {
566 role: "assistant".into(),
567 content: Some(content.into()),
568 ..Self::default()
569 }
570 }
571
572 pub fn tool(tool_call_id: impl Into<String>, content: impl Into<String>) -> Self {
574 Self {
575 role: "tool".into(),
576 content: Some(content.into()),
577 tool_call_id: Some(tool_call_id.into()),
578 ..Self::default()
579 }
580 }
581
582 pub fn parse_content<T>(&self) -> Result<Option<T>>
588 where
589 T: serde::de::DeserializeOwned,
590 {
591 self.content
592 .as_deref()
593 .map(parse_jsonish_payload)
594 .transpose()
595 }
596
597 pub fn parse_tool_arguments<T>(&self) -> Result<Option<T>>
603 where
604 T: serde::de::DeserializeOwned,
605 {
606 self.tool_calls
607 .first()
608 .map(|tool_call| parse_json_arguments(&tool_call.function.arguments))
609 .transpose()
610 }
611
612 pub fn parse_tool_arguments_by_id<T>(&self, tool_call_id: &str) -> Result<Option<T>>
618 where
619 T: serde::de::DeserializeOwned,
620 {
621 self.tool_calls
622 .iter()
623 .find(|tool_call| tool_call.id == tool_call_id)
624 .map(|tool_call| parse_json_arguments(&tool_call.function.arguments))
625 .transpose()
626 }
627}
628
629#[derive(Debug, Clone, Serialize, Deserialize, Default)]
631pub struct ChatCompletionChoice {
632 pub index: u32,
634 pub finish_reason: Option<String>,
636 pub message: ChatCompletionMessage,
638 pub logprobs: Option<ChatCompletionChoiceLogprobs>,
640 #[serde(flatten)]
642 pub extra: BTreeMap<String, Value>,
643}
644
645#[derive(Debug, Clone, Serialize, Deserialize, Default)]
647pub struct ChatCompletion {
648 pub id: String,
650 #[serde(default)]
652 pub object: String,
653 pub created: Option<i64>,
655 #[serde(default)]
657 pub model: String,
658 #[serde(default)]
660 pub choices: Vec<ChatCompletionChoice>,
661 pub usage: Option<CompletionUsage>,
663 #[serde(flatten)]
665 pub extra: BTreeMap<String, Value>,
666}
667
668impl ChatCompletion {
669 pub fn ensure_not_truncated(&self) -> Result<&Self> {
675 for choice in &self.choices {
676 match choice.finish_reason.as_deref() {
677 Some("length") => return Err(crate::LengthFinishReasonError.into()),
678 Some("content_filter") => return Err(crate::ContentFilterFinishReasonError.into()),
679 _ => {}
680 }
681 }
682 Ok(self)
683 }
684}
685
686#[derive(Debug, Clone, Serialize, Deserialize, Default)]
688pub struct ChatCompletionChunkDelta {
689 pub role: Option<String>,
691 pub content: Option<String>,
693 pub refusal: Option<String>,
695 pub reasoning_content: Option<String>,
697 #[serde(default)]
699 pub reasoning_details: Vec<ChatReasoningDetail>,
700 #[serde(default)]
702 pub tool_calls: Vec<ChatCompletionToolCallDelta>,
703 #[serde(flatten)]
705 pub extra: BTreeMap<String, Value>,
706}
707
708#[derive(Debug, Clone, Serialize, Deserialize, Default)]
710pub struct ChatCompletionChunkChoice {
711 pub index: u32,
713 pub delta: ChatCompletionChunkDelta,
715 pub finish_reason: Option<String>,
717 pub logprobs: Option<ChatCompletionChoiceLogprobs>,
719 #[serde(flatten)]
721 pub extra: BTreeMap<String, Value>,
722}
723
724#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
726pub struct ChatContentDeltaEvent {
727 pub choice_index: u32,
729 pub delta: String,
731}
732
733#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
735pub struct ChatRefusalDeltaEvent {
736 pub choice_index: u32,
738 pub delta: String,
740}
741
742#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
744pub struct ChatToolArgumentsDeltaEvent {
745 pub choice_index: u32,
747 pub tool_call_index: u32,
749 pub name: Option<String>,
751 pub delta: String,
753}
754
755#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
757pub struct ChatLogProbsDeltaEvent {
758 pub choice_index: u32,
760 pub values: Vec<ChatCompletionTokenLogprob>,
762}
763
764#[derive(Debug, Clone, Serialize, Deserialize, Default)]
766pub struct ChatCompletionChunk {
767 pub id: String,
769 #[serde(default)]
771 pub object: String,
772 pub created: Option<i64>,
774 #[serde(default)]
776 pub model: String,
777 #[serde(default)]
779 pub choices: Vec<ChatCompletionChunkChoice>,
780 #[serde(flatten)]
782 pub extra: BTreeMap<String, Value>,
783}
784
785impl ChatCompletionChunk {
786 pub fn content_deltas(&self) -> Vec<ChatContentDeltaEvent> {
788 self.choices
789 .iter()
790 .filter_map(|choice| {
791 choice
792 .delta
793 .content
794 .as_ref()
795 .map(|delta| ChatContentDeltaEvent {
796 choice_index: choice.index,
797 delta: delta.clone(),
798 })
799 })
800 .collect()
801 }
802
803 pub fn refusal_deltas(&self) -> Vec<ChatRefusalDeltaEvent> {
805 self.choices
806 .iter()
807 .filter_map(|choice| {
808 choice
809 .delta
810 .refusal
811 .as_ref()
812 .map(|delta| ChatRefusalDeltaEvent {
813 choice_index: choice.index,
814 delta: delta.clone(),
815 })
816 })
817 .collect()
818 }
819
820 pub fn tool_argument_deltas(&self) -> Vec<ChatToolArgumentsDeltaEvent> {
822 self.choices
823 .iter()
824 .flat_map(|choice| {
825 choice.delta.tool_calls.iter().filter_map(|tool_call| {
826 let delta = tool_call.function.as_ref()?.arguments.clone()?;
827 Some(ChatToolArgumentsDeltaEvent {
828 choice_index: choice.index,
829 tool_call_index: tool_call.index.unwrap_or_default(),
830 name: tool_call
831 .function
832 .as_ref()
833 .and_then(|function| function.name.clone()),
834 delta,
835 })
836 })
837 })
838 .collect()
839 }
840
841 pub fn logprobs_content_deltas(&self) -> Vec<ChatLogProbsDeltaEvent> {
843 extract_logprobs(self, "content")
844 }
845
846 pub fn logprobs_refusal_deltas(&self) -> Vec<ChatLogProbsDeltaEvent> {
848 extract_logprobs(self, "refusal")
849 }
850}
851
852fn extract_logprobs(chunk: &ChatCompletionChunk, field_name: &str) -> Vec<ChatLogProbsDeltaEvent> {
853 chunk
854 .choices
855 .iter()
856 .filter_map(|choice| {
857 let values = choice
858 .logprobs
859 .as_ref()
860 .and_then(|logprobs| logprobs.values(field_name))?
861 .to_vec();
862 Some(ChatLogProbsDeltaEvent {
863 choice_index: choice.index,
864 values,
865 })
866 })
867 .collect()
868}
869
870#[derive(Debug, Clone, Serialize, Deserialize)]
872pub struct ChatToolDefinition {
873 #[serde(rename = "type")]
875 pub tool_type: String,
876 pub function: ChatToolFunction,
878}
879
880impl ChatToolDefinition {
881 #[cfg(feature = "tool-runner")]
882 fn from_tool(tool: &ToolDefinition) -> Self {
883 Self {
884 tool_type: "function".into(),
885 function: ChatToolFunction {
886 name: tool.name.clone(),
887 description: tool.description.clone(),
888 parameters: tool.parameters.clone(),
889 },
890 }
891 }
892
893 fn as_response_tool_value(&self) -> Value {
895 serde_json::json!({
896 "type": self.tool_type,
897 "name": self.function.name,
898 "description": self.function.description,
899 "parameters": self.function.parameters,
900 })
901 }
902}
903
904#[derive(Debug, Clone, Serialize, Deserialize)]
906pub struct ChatToolFunction {
907 pub name: String,
909 pub description: Option<String>,
911 pub parameters: JsonPayload,
913}
914
915#[derive(Debug, Clone, Serialize, Deserialize, Default)]
917pub struct ChatCompletionCreateParams {
918 #[serde(skip_serializing_if = "Option::is_none")]
920 pub model: Option<String>,
921 #[serde(default, skip_serializing_if = "Vec::is_empty")]
923 pub messages: Vec<ChatCompletionMessage>,
924 #[serde(skip_serializing_if = "Option::is_none")]
926 pub temperature: Option<f32>,
927 #[serde(skip_serializing_if = "Option::is_none")]
929 pub n: Option<u32>,
930 #[serde(skip_serializing_if = "Option::is_none")]
932 pub max_tokens: Option<u32>,
933 #[serde(default, skip_serializing_if = "Vec::is_empty")]
935 pub tools: Vec<ChatToolDefinition>,
936 #[serde(skip_serializing_if = "Option::is_none")]
938 pub tool_choice: Option<ChatToolChoice>,
939 #[serde(skip_serializing_if = "Option::is_none")]
941 pub stream: Option<bool>,
942}
943
944#[derive(Debug, Clone, Serialize, Deserialize, Default)]
946pub struct Response {
947 pub id: String,
949 pub created_at: Option<u64>,
951 #[serde(default)]
953 pub object: String,
954 pub model: Option<String>,
956 pub status: Option<String>,
958 pub error: Option<ResponseError>,
960 pub incomplete_details: Option<ResponseIncompleteDetails>,
962 pub metadata: Option<BTreeMap<String, String>>,
964 #[serde(default)]
966 pub output: Vec<ResponseOutputItem>,
967 pub usage: Option<ResponseUsage>,
969 #[serde(flatten)]
971 pub extra: BTreeMap<String, Value>,
972}
973
974impl Response {
975 pub fn output_text(&self) -> Option<String> {
977 for item in &self.output {
978 if let Some(text) = item.output_text() {
979 return Some(text.to_owned());
980 }
981 }
982
983 self.extra
984 .get("output_text")
985 .and_then(Value::as_str)
986 .map(str::to_owned)
987 }
988}
989
990#[derive(Debug, Clone, Serialize, Deserialize, Default)]
992pub struct ResponseError {
993 pub code: Option<String>,
995 pub message: Option<String>,
997 #[serde(flatten)]
999 pub extra: BTreeMap<String, Value>,
1000}
1001
1002#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1004pub struct ResponseIncompleteDetails {
1005 pub reason: Option<String>,
1007 #[serde(flatten)]
1009 pub extra: BTreeMap<String, Value>,
1010}
1011
1012#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1014pub struct ResponseUsage {
1015 #[serde(default)]
1017 pub input_tokens: u64,
1018 pub input_tokens_details: Option<ResponseInputTokensDetails>,
1020 #[serde(default)]
1022 pub output_tokens: u64,
1023 pub output_tokens_details: Option<ResponseOutputTokensDetails>,
1025 #[serde(default)]
1027 pub total_tokens: u64,
1028 #[serde(flatten)]
1030 pub extra: BTreeMap<String, Value>,
1031}
1032
1033#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1035pub struct ResponseInputTokensDetails {
1036 pub cached_tokens: Option<u64>,
1038 #[serde(flatten)]
1040 pub extra: BTreeMap<String, Value>,
1041}
1042
1043#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1045pub struct ResponseOutputTokensDetails {
1046 pub reasoning_tokens: Option<u64>,
1048 #[serde(flatten)]
1050 pub extra: BTreeMap<String, Value>,
1051}
1052
1053#[derive(Debug, Clone, Serialize, Deserialize)]
1055#[serde(untagged)]
1056pub enum ResponseOutputItem {
1057 Known(KnownResponseOutputItem),
1059 Raw(ResponseOutputItemRaw),
1061}
1062
1063impl Default for ResponseOutputItem {
1064 fn default() -> Self {
1065 Self::Raw(ResponseOutputItemRaw::default())
1066 }
1067}
1068
1069impl ResponseOutputItem {
1070 pub fn as_message(&self) -> Option<&ResponseOutputMessage> {
1072 match self {
1073 Self::Known(KnownResponseOutputItem::Message(message)) => Some(message),
1074 _ => None,
1075 }
1076 }
1077
1078 pub fn as_function_call(&self) -> Option<&ResponseFunctionToolCall> {
1080 match self {
1081 Self::Known(KnownResponseOutputItem::FunctionCall(call)) => Some(call),
1082 _ => None,
1083 }
1084 }
1085
1086 pub fn as_raw(&self) -> Option<&Value> {
1088 match self {
1089 Self::Raw(value) => Some(value.as_raw()),
1090 _ => None,
1091 }
1092 }
1093
1094 pub fn output_text(&self) -> Option<&str> {
1096 match self {
1097 Self::Known(KnownResponseOutputItem::OutputText(text)) => Some(text.text.as_str()),
1098 Self::Known(KnownResponseOutputItem::Message(message)) => message
1099 .content
1100 .iter()
1101 .find_map(ResponseOutputContentPart::text),
1102 Self::Raw(value) => {
1103 let value = value.as_raw();
1104 if let Some(text) = value.get("text").and_then(Value::as_str) {
1105 return Some(text);
1106 }
1107 value
1108 .get("content")
1109 .and_then(Value::as_array)
1110 .and_then(|content| {
1111 content
1112 .iter()
1113 .find_map(|item| item.get("text").and_then(Value::as_str))
1114 })
1115 }
1116 _ => None,
1117 }
1118 }
1119}
1120
1121#[derive(Debug, Clone, Serialize, Deserialize)]
1123#[serde(tag = "type", rename_all = "snake_case")]
1124pub enum KnownResponseOutputItem {
1125 Message(ResponseOutputMessage),
1127 FunctionCall(ResponseFunctionToolCall),
1129 OutputText(ResponseOutputText),
1131 Refusal(ResponseOutputRefusal),
1133}
1134
1135#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1137pub struct ResponseOutputMessage {
1138 pub id: String,
1140 #[serde(default)]
1142 pub content: Vec<ResponseOutputContentPart>,
1143 pub role: Option<String>,
1145 pub status: Option<String>,
1147 pub phase: Option<String>,
1149 #[serde(flatten)]
1151 pub extra: BTreeMap<String, Value>,
1152}
1153
1154#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1156pub struct ResponseFunctionToolCall {
1157 pub id: String,
1159 pub call_id: Option<String>,
1161 pub name: Option<String>,
1163 #[serde(default)]
1165 pub arguments: String,
1166 pub status: Option<String>,
1168 #[serde(flatten)]
1170 pub extra: BTreeMap<String, Value>,
1171}
1172
1173#[derive(Debug, Clone, Serialize, Deserialize)]
1175#[serde(untagged)]
1176pub enum ResponseOutputContentPart {
1177 Known(KnownResponseOutputContentPart),
1179 Raw(ResponseOutputContentPartRaw),
1181}
1182
1183impl Default for ResponseOutputContentPart {
1184 fn default() -> Self {
1185 Self::Raw(ResponseOutputContentPartRaw::default())
1186 }
1187}
1188
1189impl ResponseOutputContentPart {
1190 pub fn as_output_text(&self) -> Option<&ResponseOutputText> {
1192 match self {
1193 Self::Known(KnownResponseOutputContentPart::OutputText(text)) => Some(text),
1194 _ => None,
1195 }
1196 }
1197
1198 pub fn text(&self) -> Option<&str> {
1200 match self {
1201 Self::Known(KnownResponseOutputContentPart::OutputText(text)) => {
1202 Some(text.text.as_str())
1203 }
1204 Self::Raw(value) => value.as_raw().get("text").and_then(Value::as_str),
1205 _ => None,
1206 }
1207 }
1208}
1209
1210#[derive(Debug, Clone, Serialize, Deserialize)]
1212#[serde(tag = "type", rename_all = "snake_case")]
1213pub enum KnownResponseOutputContentPart {
1214 OutputText(ResponseOutputText),
1216 Refusal(ResponseOutputRefusal),
1218}
1219
1220#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1222pub struct ResponseOutputTextFileCitation {
1223 pub file_id: String,
1225 pub filename: String,
1227 pub index: u64,
1229 #[serde(flatten)]
1231 pub extra: BTreeMap<String, Value>,
1232}
1233
1234#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1236pub struct ResponseOutputTextUrlCitation {
1237 pub end_index: u64,
1239 pub start_index: u64,
1241 pub title: String,
1243 pub url: String,
1245 #[serde(flatten)]
1247 pub extra: BTreeMap<String, Value>,
1248}
1249
1250#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1252pub struct ResponseOutputTextContainerFileCitation {
1253 pub container_id: String,
1255 pub end_index: u64,
1257 pub file_id: String,
1259 pub filename: String,
1261 pub start_index: u64,
1263 #[serde(flatten)]
1265 pub extra: BTreeMap<String, Value>,
1266}
1267
1268#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1270pub struct ResponseOutputTextFilePath {
1271 pub file_id: String,
1273 pub index: u64,
1275 #[serde(flatten)]
1277 pub extra: BTreeMap<String, Value>,
1278}
1279
1280#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1282#[serde(tag = "type", rename_all = "snake_case")]
1283pub enum KnownResponseOutputTextAnnotation {
1284 FileCitation(ResponseOutputTextFileCitation),
1286 UrlCitation(ResponseOutputTextUrlCitation),
1288 ContainerFileCitation(ResponseOutputTextContainerFileCitation),
1290 FilePath(ResponseOutputTextFilePath),
1292}
1293
1294#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1296pub struct ResponseOutputTextAnnotationUnknown {
1297 #[serde(rename = "type")]
1299 pub annotation_type: Option<String>,
1300 #[serde(flatten)]
1302 pub extra: BTreeMap<String, Value>,
1303}
1304
1305#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1307#[serde(untagged)]
1308pub enum ResponseOutputTextAnnotation {
1309 Known(KnownResponseOutputTextAnnotation),
1311 Unknown(ResponseOutputTextAnnotationUnknown),
1313}
1314
1315impl Default for ResponseOutputTextAnnotation {
1316 fn default() -> Self {
1317 Self::Unknown(ResponseOutputTextAnnotationUnknown::default())
1318 }
1319}
1320
1321impl ResponseOutputTextAnnotation {
1322 pub fn kind(&self) -> Option<&str> {
1324 match self {
1325 Self::Known(KnownResponseOutputTextAnnotation::FileCitation(_)) => {
1326 Some("file_citation")
1327 }
1328 Self::Known(KnownResponseOutputTextAnnotation::UrlCitation(_)) => Some("url_citation"),
1329 Self::Known(KnownResponseOutputTextAnnotation::ContainerFileCitation(_)) => {
1330 Some("container_file_citation")
1331 }
1332 Self::Known(KnownResponseOutputTextAnnotation::FilePath(_)) => Some("file_path"),
1333 Self::Unknown(annotation) => annotation.annotation_type.as_deref(),
1334 }
1335 }
1336}
1337
1338#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1340pub struct ResponseOutputTextTopLogprob {
1341 #[serde(default)]
1343 pub token: String,
1344 #[serde(default)]
1346 pub bytes: Vec<u8>,
1347 #[serde(default)]
1349 pub logprob: f64,
1350 #[serde(flatten)]
1352 pub extra: BTreeMap<String, Value>,
1353}
1354
1355#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1357pub struct ResponseOutputTextLogprob {
1358 #[serde(default)]
1360 pub token: String,
1361 #[serde(default)]
1363 pub bytes: Vec<u8>,
1364 #[serde(default)]
1366 pub logprob: f64,
1367 #[serde(default)]
1369 pub top_logprobs: Vec<ResponseOutputTextTopLogprob>,
1370 #[serde(flatten)]
1372 pub extra: BTreeMap<String, Value>,
1373}
1374
1375#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1377pub struct ResponseOutputText {
1378 #[serde(default)]
1380 pub annotations: Vec<ResponseOutputTextAnnotation>,
1381 #[serde(default)]
1383 pub text: String,
1384 pub logprobs: Option<Vec<ResponseOutputTextLogprob>>,
1386 #[serde(flatten)]
1388 pub extra: BTreeMap<String, Value>,
1389}
1390
1391#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1393pub struct ResponseOutputRefusal {
1394 #[serde(default)]
1396 pub refusal: String,
1397 #[serde(flatten)]
1399 pub extra: BTreeMap<String, Value>,
1400}
1401
1402#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1404pub struct ResponseCreateParams {
1405 #[serde(skip_serializing_if = "Option::is_none")]
1407 pub model: Option<String>,
1408 #[serde(skip_serializing_if = "Option::is_none")]
1410 pub input: Option<ResponseInputPayload>,
1411 #[serde(skip_serializing_if = "Option::is_none")]
1413 pub temperature: Option<f32>,
1414 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1416 pub tools: Vec<ChatToolDefinition>,
1417 #[serde(skip_serializing_if = "Option::is_none")]
1419 pub stream: Option<bool>,
1420}
1421
1422fn default_function_type() -> String {
1423 "function".into()
1424}
1425
1426fn parse_jsonish_payload<T>(payload: &str) -> Result<T>
1427where
1428 T: serde::de::DeserializeOwned,
1429{
1430 let trimmed = payload.trim();
1431 let normalized = trimmed
1432 .strip_prefix("```json")
1433 .or_else(|| trimmed.strip_prefix("```"))
1434 .map(|value| value.trim())
1435 .and_then(|value| value.strip_suffix("```"))
1436 .map_or(trimmed, str::trim);
1437 serde_json::from_str(normalized).map_err(|error| {
1438 Error::Serialization(crate::SerializationError::new(format!(
1439 "结构化 JSON 解析失败: {error}"
1440 )))
1441 })
1442}
1443
1444fn parse_json_arguments<T>(arguments: &str) -> Result<T>
1445where
1446 T: serde::de::DeserializeOwned,
1447{
1448 serde_json::from_str(arguments).map_err(|error| {
1449 Error::Serialization(crate::SerializationError::new(format!(
1450 "工具参数 JSON 解析失败: {error}"
1451 )))
1452 })
1453}
1454
1455handle!(
1456 CompletionsResource
1458);
1459handle!(
1460 ChatResource
1462);
1463handle!(
1464 ChatCompletionsResource
1466);
1467handle!(
1468 ChatCompletionMessagesResource
1470);
1471handle!(
1472 EmbeddingsResource
1474);
1475handle!(
1476 FilesResource
1478);
1479handle!(
1480 ImagesResource
1482);
1483handle!(
1484 AudioResource
1486);
1487handle!(
1488 AudioSpeechResource
1490);
1491handle!(
1492 AudioTranscriptionsResource
1494);
1495handle!(
1496 AudioTranslationsResource
1498);
1499handle!(
1500 ModerationsResource
1502);
1503handle!(
1504 ModelsResource
1506);
1507handle!(
1508 FineTuningResource
1510);
1511handle!(
1512 FineTuningJobsResource
1514);
1515handle!(
1516 FineTuningJobCheckpointsResource
1518);
1519handle!(
1520 FineTuningCheckpointPermissionsResource
1522);
1523handle!(
1524 FineTuningAlphaResource
1526);
1527handle!(
1528 FineTuningAlphaGradersResource
1530);
1531handle!(
1532 GradersResource
1534);
1535handle!(
1536 VectorStoresResource
1538);
1539handle!(
1540 VectorStoreFilesResource
1542);
1543handle!(
1544 VectorStoreFileBatchesResource
1546);
1547handle!(
1548 BatchesResource
1550);
1551handle!(
1552 UploadsResource
1554);
1555handle!(
1556 UploadPartsResource
1558);
1559handle!(
1560 ResponsesResource
1562);
1563handle!(
1564 ResponseInputItemsResource
1566);
1567handle!(
1568 ResponseInputTokensResource
1570);
1571handle!(
1572 RealtimeResource
1574);
1575handle!(
1576 RealtimeClientSecretsResource
1578);
1579handle!(
1580 RealtimeCallsResource
1582);
1583handle!(
1584 ConversationsResource
1586);
1587handle!(
1588 ConversationItemsResource
1590);
1591handle!(
1592 EvalsResource
1594);
1595handle!(
1596 EvalRunsResource
1598);
1599handle!(
1600 EvalRunOutputItemsResource
1602);
1603handle!(
1604 ContainersResource
1606);
1607handle!(
1608 ContainerFilesResource
1610);
1611handle!(
1612 ContainerFilesContentResource
1614);
1615handle!(
1616 SkillsResource
1618);
1619handle!(
1620 SkillsContentResource
1622);
1623handle!(
1624 SkillVersionsResource
1626);
1627handle!(
1628 SkillVersionsContentResource
1630);
1631handle!(
1632 VideosResource
1634);
1635handle!(
1636 WebhooksResource
1638);
1639handle!(
1640 BetaResource
1642);
1643handle!(
1644 BetaAssistantsResource
1646);
1647handle!(
1648 BetaThreadsResource
1650);
1651handle!(
1652 BetaThreadMessagesResource
1654);
1655handle!(
1656 BetaThreadRunsResource
1658);
1659handle!(
1660 BetaThreadRunStepsResource
1662);
1663handle!(
1664 BetaChatkitResource
1666);
1667handle!(
1668 BetaChatkitSessionsResource
1670);
1671handle!(
1672 BetaChatkitThreadsResource
1674);
1675handle!(
1676 BetaRealtimeResource
1678);
1679handle!(
1680 BetaRealtimeSessionsResource
1682);
1683handle!(
1684 BetaRealtimeTranscriptionSessionsResource
1686);