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 ChatMessageContentPart
298);
299json_payload_wrapper!(
300 ChatToolChoice
302);
303json_payload_wrapper!(
304 ResponseInputPayload
306);
307json_payload_wrapper!(
308 ResponseInputItemPayload
310);
311json_payload_wrapper!(
312 RealtimeSessionPayload
314);
315json_payload_wrapper!(
316 ResponseOutputItemRaw
318);
319json_payload_wrapper!(
320 ResponseOutputContentPartRaw
322);
323
324#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
326#[serde(rename_all = "snake_case")]
327pub enum ChatToolChoiceMode {
328 None,
330 Auto,
332 Required,
334}
335
336impl From<ChatToolChoiceMode> for ChatToolChoice {
337 fn from(mode: ChatToolChoiceMode) -> Self {
338 let value = match mode {
339 ChatToolChoiceMode::None => Value::String("none".into()),
340 ChatToolChoiceMode::Auto => Value::String("auto".into()),
341 ChatToolChoiceMode::Required => Value::String("required".into()),
342 };
343 Self::from(value)
344 }
345}
346
347impl From<String> for ResponseInputPayload {
348 fn from(value: String) -> Self {
349 Self::from(Value::String(value))
350 }
351}
352
353impl From<&str> for ResponseInputPayload {
354 fn from(value: &str) -> Self {
355 Self::from(Value::String(value.into()))
356 }
357}
358
359impl From<Vec<ResponseInputItemPayload>> for ResponseInputPayload {
360 fn from(items: Vec<ResponseInputItemPayload>) -> Self {
361 Self::from(Value::Array(items.into_iter().map(Value::from).collect()))
362 }
363}
364
365impl ChatToolChoice {
366 pub fn none() -> Self {
368 ChatToolChoiceMode::None.into()
369 }
370
371 pub fn auto() -> Self {
373 ChatToolChoiceMode::Auto.into()
374 }
375
376 pub fn required() -> Self {
378 ChatToolChoiceMode::Required.into()
379 }
380
381 pub fn function(name: impl Into<String>) -> Self {
383 serde_json::json!({
384 "type": "function",
385 "function": {
386 "name": name.into(),
387 },
388 })
389 .into()
390 }
391
392 pub fn custom(name: impl Into<String>) -> Self {
394 serde_json::json!({
395 "type": "custom",
396 "custom": {
397 "name": name.into(),
398 },
399 })
400 .into()
401 }
402
403 pub fn mode_name(&self) -> Option<&str> {
405 self.0.as_str()
406 }
407}
408
409#[derive(Debug, Clone, Serialize, Deserialize, Default)]
411pub struct ChatCompletionFunctionCall {
412 pub name: String,
414 #[serde(default)]
416 pub arguments: String,
417}
418
419#[derive(Debug, Clone, Serialize, Deserialize, Default)]
421pub struct ChatCompletionToolCall {
422 pub id: String,
424 #[serde(rename = "type", default = "default_function_type")]
426 pub call_type: String,
427 pub function: ChatCompletionFunctionCall,
429 #[serde(flatten)]
431 pub extra: BTreeMap<String, Value>,
432}
433
434#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
436pub struct ChatCompletionTokenTopLogprob {
437 #[serde(default)]
439 pub token: String,
440 pub bytes: Option<Vec<u8>>,
442 #[serde(default)]
444 pub logprob: f64,
445 #[serde(flatten)]
447 pub extra: BTreeMap<String, Value>,
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
452pub struct ChatCompletionTokenLogprob {
453 #[serde(default)]
455 pub token: String,
456 pub bytes: Option<Vec<u8>>,
458 #[serde(default)]
460 pub logprob: f64,
461 #[serde(default)]
463 pub top_logprobs: Vec<ChatCompletionTokenTopLogprob>,
464 #[serde(flatten)]
466 pub extra: BTreeMap<String, Value>,
467}
468
469#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
471pub struct ChatCompletionChoiceLogprobs {
472 #[serde(default, skip_serializing_if = "Vec::is_empty")]
474 pub content: Vec<ChatCompletionTokenLogprob>,
475 #[serde(default, skip_serializing_if = "Vec::is_empty")]
477 pub refusal: Vec<ChatCompletionTokenLogprob>,
478 #[serde(flatten)]
480 pub extra: BTreeMap<String, Value>,
481}
482
483impl ChatCompletionChoiceLogprobs {
484 pub fn values(&self, field_name: &str) -> Option<&[ChatCompletionTokenLogprob]> {
486 match field_name {
487 "content" if !self.content.is_empty() => Some(&self.content),
488 "refusal" if !self.refusal.is_empty() => Some(&self.refusal),
489 _ => None,
490 }
491 }
492}
493
494#[derive(Debug, Clone, Serialize, Deserialize, Default)]
496pub struct ChatCompletionFunctionCallDelta {
497 pub name: Option<String>,
499 pub arguments: Option<String>,
501}
502
503#[derive(Debug, Clone, Serialize, Deserialize, Default)]
505pub struct ChatCompletionToolCallDelta {
506 pub index: Option<u32>,
508 pub id: Option<String>,
510 #[serde(rename = "type")]
512 pub call_type: Option<String>,
513 pub function: Option<ChatCompletionFunctionCallDelta>,
515}
516
517#[derive(Debug, Clone, Serialize, Deserialize, Default)]
519pub struct ChatCompletionMessage {
520 pub role: String,
522 #[serde(skip_serializing_if = "Option::is_none")]
524 pub content: Option<String>,
525 #[serde(skip_serializing_if = "Option::is_none")]
527 pub name: Option<String>,
528 #[serde(skip_serializing_if = "Option::is_none")]
530 pub tool_call_id: Option<String>,
531 #[serde(default, skip_serializing_if = "Vec::is_empty")]
533 pub tool_calls: Vec<ChatCompletionToolCall>,
534 #[serde(skip_serializing_if = "Option::is_none")]
536 pub refusal: Option<String>,
537 #[serde(skip_serializing_if = "Option::is_none")]
539 pub reasoning_content: Option<String>,
540 #[serde(default, skip_serializing_if = "Vec::is_empty")]
542 pub reasoning_details: Vec<ChatReasoningDetail>,
543 #[serde(flatten)]
545 pub extra: BTreeMap<String, Value>,
546}
547
548impl ChatCompletionMessage {
549 pub fn system(content: impl Into<String>) -> Self {
551 Self {
552 role: "system".into(),
553 content: Some(content.into()),
554 ..Self::default()
555 }
556 }
557
558 pub fn user(content: impl Into<String>) -> Self {
560 Self {
561 role: "user".into(),
562 content: Some(content.into()),
563 ..Self::default()
564 }
565 }
566
567 pub fn user_content_parts(parts: Vec<ChatMessageContentPart>) -> Self {
569 Self::with_content_parts("user", parts)
570 }
571
572 pub fn with_content_parts(role: impl Into<String>, parts: Vec<ChatMessageContentPart>) -> Self {
574 let mut extra = BTreeMap::new();
575 extra.insert(
576 "content".into(),
577 Value::Array(parts.into_iter().map(Value::from).collect()),
578 );
579 Self {
580 role: role.into(),
581 content: None,
582 extra,
583 ..Self::default()
584 }
585 }
586
587 pub fn content_text(text: impl Into<String>) -> ChatMessageContentPart {
589 serde_json::json!({
590 "type": "text",
591 "text": text.into(),
592 })
593 .into()
594 }
595
596 pub fn content_image_url(url: impl Into<String>) -> ChatMessageContentPart {
598 serde_json::json!({
599 "type": "image_url",
600 "image_url": {
601 "url": url.into(),
602 },
603 })
604 .into()
605 }
606
607 pub fn content_video_url(url: impl Into<String>) -> ChatMessageContentPart {
609 serde_json::json!({
610 "type": "video_url",
611 "video_url": {
612 "url": url.into(),
613 },
614 })
615 .into()
616 }
617
618 pub fn content_file(file_id: impl Into<String>) -> ChatMessageContentPart {
620 serde_json::json!({
621 "type": "file",
622 "file": {
623 "file_id": file_id.into(),
624 },
625 })
626 .into()
627 }
628
629 pub fn assistant(content: impl Into<String>) -> Self {
631 Self {
632 role: "assistant".into(),
633 content: Some(content.into()),
634 ..Self::default()
635 }
636 }
637
638 pub fn tool(tool_call_id: impl Into<String>, content: impl Into<String>) -> Self {
640 Self {
641 role: "tool".into(),
642 content: Some(content.into()),
643 tool_call_id: Some(tool_call_id.into()),
644 ..Self::default()
645 }
646 }
647
648 pub fn parse_content<T>(&self) -> Result<Option<T>>
654 where
655 T: serde::de::DeserializeOwned,
656 {
657 self.content
658 .as_deref()
659 .map(parse_jsonish_payload)
660 .transpose()
661 }
662
663 pub fn parse_tool_arguments<T>(&self) -> Result<Option<T>>
669 where
670 T: serde::de::DeserializeOwned,
671 {
672 self.tool_calls
673 .first()
674 .map(|tool_call| parse_json_arguments(&tool_call.function.arguments))
675 .transpose()
676 }
677
678 pub fn parse_tool_arguments_by_id<T>(&self, tool_call_id: &str) -> Result<Option<T>>
684 where
685 T: serde::de::DeserializeOwned,
686 {
687 self.tool_calls
688 .iter()
689 .find(|tool_call| tool_call.id == tool_call_id)
690 .map(|tool_call| parse_json_arguments(&tool_call.function.arguments))
691 .transpose()
692 }
693}
694
695#[derive(Debug, Clone, Serialize, Deserialize, Default)]
697pub struct ChatCompletionChoice {
698 pub index: u32,
700 pub finish_reason: Option<String>,
702 pub message: ChatCompletionMessage,
704 pub logprobs: Option<ChatCompletionChoiceLogprobs>,
706 #[serde(flatten)]
708 pub extra: BTreeMap<String, Value>,
709}
710
711#[derive(Debug, Clone, Serialize, Deserialize, Default)]
713pub struct ChatCompletion {
714 pub id: String,
716 #[serde(default)]
718 pub object: String,
719 pub created: Option<i64>,
721 #[serde(default)]
723 pub model: String,
724 #[serde(default)]
726 pub choices: Vec<ChatCompletionChoice>,
727 pub usage: Option<CompletionUsage>,
729 #[serde(flatten)]
731 pub extra: BTreeMap<String, Value>,
732}
733
734impl ChatCompletion {
735 pub fn ensure_not_truncated(&self) -> Result<&Self> {
741 for choice in &self.choices {
742 match choice.finish_reason.as_deref() {
743 Some("length") => return Err(crate::LengthFinishReasonError.into()),
744 Some("content_filter") => return Err(crate::ContentFilterFinishReasonError.into()),
745 _ => {}
746 }
747 }
748 Ok(self)
749 }
750}
751
752#[derive(Debug, Clone, Serialize, Deserialize, Default)]
754pub struct ChatCompletionChunkDelta {
755 pub role: Option<String>,
757 pub content: Option<String>,
759 pub refusal: Option<String>,
761 pub reasoning_content: Option<String>,
763 #[serde(default)]
765 pub reasoning_details: Vec<ChatReasoningDetail>,
766 #[serde(default)]
768 pub tool_calls: Vec<ChatCompletionToolCallDelta>,
769 #[serde(flatten)]
771 pub extra: BTreeMap<String, Value>,
772}
773
774#[derive(Debug, Clone, Serialize, Deserialize, Default)]
776pub struct ChatCompletionChunkChoice {
777 pub index: u32,
779 pub delta: ChatCompletionChunkDelta,
781 pub finish_reason: Option<String>,
783 pub logprobs: Option<ChatCompletionChoiceLogprobs>,
785 #[serde(flatten)]
787 pub extra: BTreeMap<String, Value>,
788}
789
790#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
792pub struct ChatContentDeltaEvent {
793 pub choice_index: u32,
795 pub delta: String,
797}
798
799#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
801pub struct ChatRefusalDeltaEvent {
802 pub choice_index: u32,
804 pub delta: String,
806}
807
808#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
810pub struct ChatToolArgumentsDeltaEvent {
811 pub choice_index: u32,
813 pub tool_call_index: u32,
815 pub name: Option<String>,
817 pub delta: String,
819}
820
821#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
823pub struct ChatLogProbsDeltaEvent {
824 pub choice_index: u32,
826 pub values: Vec<ChatCompletionTokenLogprob>,
828}
829
830#[derive(Debug, Clone, Serialize, Deserialize, Default)]
832pub struct ChatCompletionChunk {
833 pub id: String,
835 #[serde(default)]
837 pub object: String,
838 pub created: Option<i64>,
840 #[serde(default)]
842 pub model: String,
843 #[serde(default)]
845 pub choices: Vec<ChatCompletionChunkChoice>,
846 #[serde(flatten)]
848 pub extra: BTreeMap<String, Value>,
849}
850
851impl ChatCompletionChunk {
852 pub fn content_deltas(&self) -> Vec<ChatContentDeltaEvent> {
854 self.choices
855 .iter()
856 .filter_map(|choice| {
857 choice
858 .delta
859 .content
860 .as_ref()
861 .map(|delta| ChatContentDeltaEvent {
862 choice_index: choice.index,
863 delta: delta.clone(),
864 })
865 })
866 .collect()
867 }
868
869 pub fn refusal_deltas(&self) -> Vec<ChatRefusalDeltaEvent> {
871 self.choices
872 .iter()
873 .filter_map(|choice| {
874 choice
875 .delta
876 .refusal
877 .as_ref()
878 .map(|delta| ChatRefusalDeltaEvent {
879 choice_index: choice.index,
880 delta: delta.clone(),
881 })
882 })
883 .collect()
884 }
885
886 pub fn tool_argument_deltas(&self) -> Vec<ChatToolArgumentsDeltaEvent> {
888 self.choices
889 .iter()
890 .flat_map(|choice| {
891 choice.delta.tool_calls.iter().filter_map(|tool_call| {
892 let delta = tool_call.function.as_ref()?.arguments.clone()?;
893 Some(ChatToolArgumentsDeltaEvent {
894 choice_index: choice.index,
895 tool_call_index: tool_call.index.unwrap_or_default(),
896 name: tool_call
897 .function
898 .as_ref()
899 .and_then(|function| function.name.clone()),
900 delta,
901 })
902 })
903 })
904 .collect()
905 }
906
907 pub fn logprobs_content_deltas(&self) -> Vec<ChatLogProbsDeltaEvent> {
909 extract_logprobs(self, "content")
910 }
911
912 pub fn logprobs_refusal_deltas(&self) -> Vec<ChatLogProbsDeltaEvent> {
914 extract_logprobs(self, "refusal")
915 }
916}
917
918fn extract_logprobs(chunk: &ChatCompletionChunk, field_name: &str) -> Vec<ChatLogProbsDeltaEvent> {
919 chunk
920 .choices
921 .iter()
922 .filter_map(|choice| {
923 let values = choice
924 .logprobs
925 .as_ref()
926 .and_then(|logprobs| logprobs.values(field_name))?
927 .to_vec();
928 Some(ChatLogProbsDeltaEvent {
929 choice_index: choice.index,
930 values,
931 })
932 })
933 .collect()
934}
935
936#[derive(Debug, Clone, Serialize, Deserialize)]
938pub struct ChatToolDefinition {
939 #[serde(rename = "type")]
941 pub tool_type: String,
942 pub function: ChatToolFunction,
944}
945
946impl ChatToolDefinition {
947 #[cfg(feature = "tool-runner")]
948 fn from_tool(tool: &ToolDefinition) -> Self {
949 Self {
950 tool_type: "function".into(),
951 function: ChatToolFunction {
952 name: tool.name.clone(),
953 description: tool.description.clone(),
954 parameters: tool.parameters.clone(),
955 },
956 }
957 }
958
959 fn as_response_tool_value(&self) -> Value {
961 serde_json::json!({
962 "type": self.tool_type,
963 "name": self.function.name,
964 "description": self.function.description,
965 "parameters": self.function.parameters,
966 })
967 }
968}
969
970#[derive(Debug, Clone, Serialize, Deserialize)]
972pub struct ChatToolFunction {
973 pub name: String,
975 pub description: Option<String>,
977 pub parameters: JsonPayload,
979}
980
981#[derive(Debug, Clone, Serialize, Deserialize, Default)]
983pub struct ChatCompletionCreateParams {
984 #[serde(skip_serializing_if = "Option::is_none")]
986 pub model: Option<String>,
987 #[serde(default, skip_serializing_if = "Vec::is_empty")]
989 pub messages: Vec<ChatCompletionMessage>,
990 #[serde(skip_serializing_if = "Option::is_none")]
992 pub temperature: Option<f32>,
993 #[serde(skip_serializing_if = "Option::is_none")]
995 pub n: Option<u32>,
996 #[serde(skip_serializing_if = "Option::is_none")]
998 pub max_tokens: Option<u32>,
999 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1001 pub tools: Vec<ChatToolDefinition>,
1002 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub tool_choice: Option<ChatToolChoice>,
1005 #[serde(skip_serializing_if = "Option::is_none")]
1007 pub stream: Option<bool>,
1008}
1009
1010#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1012pub struct Response {
1013 pub id: String,
1015 pub created_at: Option<u64>,
1017 #[serde(default)]
1019 pub object: String,
1020 pub model: Option<String>,
1022 pub status: Option<String>,
1024 pub error: Option<ResponseError>,
1026 pub incomplete_details: Option<ResponseIncompleteDetails>,
1028 pub metadata: Option<BTreeMap<String, String>>,
1030 #[serde(default)]
1032 pub output: Vec<ResponseOutputItem>,
1033 pub usage: Option<ResponseUsage>,
1035 #[serde(flatten)]
1037 pub extra: BTreeMap<String, Value>,
1038}
1039
1040impl Response {
1041 pub fn output_text(&self) -> Option<String> {
1043 for item in &self.output {
1044 if let Some(text) = item.output_text() {
1045 return Some(text.to_owned());
1046 }
1047 }
1048
1049 self.extra
1050 .get("output_text")
1051 .and_then(Value::as_str)
1052 .map(str::to_owned)
1053 }
1054}
1055
1056#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1058pub struct ResponseError {
1059 pub code: Option<String>,
1061 pub message: Option<String>,
1063 #[serde(flatten)]
1065 pub extra: BTreeMap<String, Value>,
1066}
1067
1068#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1070pub struct ResponseIncompleteDetails {
1071 pub reason: Option<String>,
1073 #[serde(flatten)]
1075 pub extra: BTreeMap<String, Value>,
1076}
1077
1078#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1080pub struct ResponseUsage {
1081 #[serde(default)]
1083 pub input_tokens: u64,
1084 pub input_tokens_details: Option<ResponseInputTokensDetails>,
1086 #[serde(default)]
1088 pub output_tokens: u64,
1089 pub output_tokens_details: Option<ResponseOutputTokensDetails>,
1091 #[serde(default)]
1093 pub total_tokens: u64,
1094 #[serde(flatten)]
1096 pub extra: BTreeMap<String, Value>,
1097}
1098
1099#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1101pub struct ResponseInputTokensDetails {
1102 pub cached_tokens: Option<u64>,
1104 #[serde(flatten)]
1106 pub extra: BTreeMap<String, Value>,
1107}
1108
1109#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1111pub struct ResponseOutputTokensDetails {
1112 pub reasoning_tokens: Option<u64>,
1114 #[serde(flatten)]
1116 pub extra: BTreeMap<String, Value>,
1117}
1118
1119#[derive(Debug, Clone, Serialize, Deserialize)]
1121#[serde(untagged)]
1122pub enum ResponseOutputItem {
1123 Known(KnownResponseOutputItem),
1125 Raw(ResponseOutputItemRaw),
1127}
1128
1129impl Default for ResponseOutputItem {
1130 fn default() -> Self {
1131 Self::Raw(ResponseOutputItemRaw::default())
1132 }
1133}
1134
1135impl ResponseOutputItem {
1136 pub fn as_message(&self) -> Option<&ResponseOutputMessage> {
1138 match self {
1139 Self::Known(KnownResponseOutputItem::Message(message)) => Some(message),
1140 _ => None,
1141 }
1142 }
1143
1144 pub fn as_function_call(&self) -> Option<&ResponseFunctionToolCall> {
1146 match self {
1147 Self::Known(KnownResponseOutputItem::FunctionCall(call)) => Some(call),
1148 _ => None,
1149 }
1150 }
1151
1152 pub fn as_raw(&self) -> Option<&Value> {
1154 match self {
1155 Self::Raw(value) => Some(value.as_raw()),
1156 _ => None,
1157 }
1158 }
1159
1160 pub fn output_text(&self) -> Option<&str> {
1162 match self {
1163 Self::Known(KnownResponseOutputItem::OutputText(text)) => Some(text.text.as_str()),
1164 Self::Known(KnownResponseOutputItem::Message(message)) => message
1165 .content
1166 .iter()
1167 .find_map(ResponseOutputContentPart::text),
1168 Self::Raw(value) => {
1169 let value = value.as_raw();
1170 if let Some(text) = value.get("text").and_then(Value::as_str) {
1171 return Some(text);
1172 }
1173 value
1174 .get("content")
1175 .and_then(Value::as_array)
1176 .and_then(|content| {
1177 content
1178 .iter()
1179 .find_map(|item| item.get("text").and_then(Value::as_str))
1180 })
1181 }
1182 _ => None,
1183 }
1184 }
1185}
1186
1187#[derive(Debug, Clone, Serialize, Deserialize)]
1189#[serde(tag = "type", rename_all = "snake_case")]
1190pub enum KnownResponseOutputItem {
1191 Message(ResponseOutputMessage),
1193 FunctionCall(ResponseFunctionToolCall),
1195 OutputText(ResponseOutputText),
1197 Refusal(ResponseOutputRefusal),
1199}
1200
1201#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1203pub struct ResponseOutputMessage {
1204 pub id: String,
1206 #[serde(default)]
1208 pub content: Vec<ResponseOutputContentPart>,
1209 pub role: Option<String>,
1211 pub status: Option<String>,
1213 pub phase: Option<String>,
1215 #[serde(flatten)]
1217 pub extra: BTreeMap<String, Value>,
1218}
1219
1220#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1222pub struct ResponseFunctionToolCall {
1223 pub id: String,
1225 pub call_id: Option<String>,
1227 pub name: Option<String>,
1229 #[serde(default)]
1231 pub arguments: String,
1232 pub status: Option<String>,
1234 #[serde(flatten)]
1236 pub extra: BTreeMap<String, Value>,
1237}
1238
1239#[derive(Debug, Clone, Serialize, Deserialize)]
1241#[serde(untagged)]
1242pub enum ResponseOutputContentPart {
1243 Known(KnownResponseOutputContentPart),
1245 Raw(ResponseOutputContentPartRaw),
1247}
1248
1249impl Default for ResponseOutputContentPart {
1250 fn default() -> Self {
1251 Self::Raw(ResponseOutputContentPartRaw::default())
1252 }
1253}
1254
1255impl ResponseOutputContentPart {
1256 pub fn as_output_text(&self) -> Option<&ResponseOutputText> {
1258 match self {
1259 Self::Known(KnownResponseOutputContentPart::OutputText(text)) => Some(text),
1260 _ => None,
1261 }
1262 }
1263
1264 pub fn text(&self) -> Option<&str> {
1266 match self {
1267 Self::Known(KnownResponseOutputContentPart::OutputText(text)) => {
1268 Some(text.text.as_str())
1269 }
1270 Self::Raw(value) => value.as_raw().get("text").and_then(Value::as_str),
1271 _ => None,
1272 }
1273 }
1274}
1275
1276#[derive(Debug, Clone, Serialize, Deserialize)]
1278#[serde(tag = "type", rename_all = "snake_case")]
1279pub enum KnownResponseOutputContentPart {
1280 OutputText(ResponseOutputText),
1282 Refusal(ResponseOutputRefusal),
1284}
1285
1286#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1288pub struct ResponseOutputTextFileCitation {
1289 pub file_id: String,
1291 pub filename: String,
1293 pub index: u64,
1295 #[serde(flatten)]
1297 pub extra: BTreeMap<String, Value>,
1298}
1299
1300#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1302pub struct ResponseOutputTextUrlCitation {
1303 pub end_index: u64,
1305 pub start_index: u64,
1307 pub title: String,
1309 pub url: String,
1311 #[serde(flatten)]
1313 pub extra: BTreeMap<String, Value>,
1314}
1315
1316#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1318pub struct ResponseOutputTextContainerFileCitation {
1319 pub container_id: String,
1321 pub end_index: u64,
1323 pub file_id: String,
1325 pub filename: String,
1327 pub start_index: u64,
1329 #[serde(flatten)]
1331 pub extra: BTreeMap<String, Value>,
1332}
1333
1334#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1336pub struct ResponseOutputTextFilePath {
1337 pub file_id: String,
1339 pub index: u64,
1341 #[serde(flatten)]
1343 pub extra: BTreeMap<String, Value>,
1344}
1345
1346#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1348#[serde(tag = "type", rename_all = "snake_case")]
1349pub enum KnownResponseOutputTextAnnotation {
1350 FileCitation(ResponseOutputTextFileCitation),
1352 UrlCitation(ResponseOutputTextUrlCitation),
1354 ContainerFileCitation(ResponseOutputTextContainerFileCitation),
1356 FilePath(ResponseOutputTextFilePath),
1358}
1359
1360#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1362pub struct ResponseOutputTextAnnotationUnknown {
1363 #[serde(rename = "type")]
1365 pub annotation_type: Option<String>,
1366 #[serde(flatten)]
1368 pub extra: BTreeMap<String, Value>,
1369}
1370
1371#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1373#[serde(untagged)]
1374pub enum ResponseOutputTextAnnotation {
1375 Known(KnownResponseOutputTextAnnotation),
1377 Unknown(ResponseOutputTextAnnotationUnknown),
1379}
1380
1381impl Default for ResponseOutputTextAnnotation {
1382 fn default() -> Self {
1383 Self::Unknown(ResponseOutputTextAnnotationUnknown::default())
1384 }
1385}
1386
1387impl ResponseOutputTextAnnotation {
1388 pub fn kind(&self) -> Option<&str> {
1390 match self {
1391 Self::Known(KnownResponseOutputTextAnnotation::FileCitation(_)) => {
1392 Some("file_citation")
1393 }
1394 Self::Known(KnownResponseOutputTextAnnotation::UrlCitation(_)) => Some("url_citation"),
1395 Self::Known(KnownResponseOutputTextAnnotation::ContainerFileCitation(_)) => {
1396 Some("container_file_citation")
1397 }
1398 Self::Known(KnownResponseOutputTextAnnotation::FilePath(_)) => Some("file_path"),
1399 Self::Unknown(annotation) => annotation.annotation_type.as_deref(),
1400 }
1401 }
1402}
1403
1404#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1406pub struct ResponseOutputTextTopLogprob {
1407 #[serde(default)]
1409 pub token: String,
1410 #[serde(default)]
1412 pub bytes: Vec<u8>,
1413 #[serde(default)]
1415 pub logprob: f64,
1416 #[serde(flatten)]
1418 pub extra: BTreeMap<String, Value>,
1419}
1420
1421#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1423pub struct ResponseOutputTextLogprob {
1424 #[serde(default)]
1426 pub token: String,
1427 #[serde(default)]
1429 pub bytes: Vec<u8>,
1430 #[serde(default)]
1432 pub logprob: f64,
1433 #[serde(default)]
1435 pub top_logprobs: Vec<ResponseOutputTextTopLogprob>,
1436 #[serde(flatten)]
1438 pub extra: BTreeMap<String, Value>,
1439}
1440
1441#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1443pub struct ResponseOutputText {
1444 #[serde(default)]
1446 pub annotations: Vec<ResponseOutputTextAnnotation>,
1447 #[serde(default)]
1449 pub text: String,
1450 pub logprobs: Option<Vec<ResponseOutputTextLogprob>>,
1452 #[serde(flatten)]
1454 pub extra: BTreeMap<String, Value>,
1455}
1456
1457#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1459pub struct ResponseOutputRefusal {
1460 #[serde(default)]
1462 pub refusal: String,
1463 #[serde(flatten)]
1465 pub extra: BTreeMap<String, Value>,
1466}
1467
1468#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1470pub struct ResponseCreateParams {
1471 #[serde(skip_serializing_if = "Option::is_none")]
1473 pub model: Option<String>,
1474 #[serde(skip_serializing_if = "Option::is_none")]
1476 pub input: Option<ResponseInputPayload>,
1477 #[serde(skip_serializing_if = "Option::is_none")]
1479 pub temperature: Option<f32>,
1480 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1482 pub tools: Vec<ChatToolDefinition>,
1483 #[serde(skip_serializing_if = "Option::is_none")]
1485 pub stream: Option<bool>,
1486}
1487
1488fn default_function_type() -> String {
1489 "function".into()
1490}
1491
1492fn parse_jsonish_payload<T>(payload: &str) -> Result<T>
1493where
1494 T: serde::de::DeserializeOwned,
1495{
1496 let trimmed = payload.trim();
1497 let normalized = trimmed
1498 .strip_prefix("```json")
1499 .or_else(|| trimmed.strip_prefix("```"))
1500 .map(|value| value.trim())
1501 .and_then(|value| value.strip_suffix("```"))
1502 .map_or(trimmed, str::trim);
1503 serde_json::from_str(normalized).map_err(|error| {
1504 Error::Serialization(crate::SerializationError::new(format!(
1505 "结构化 JSON 解析失败: {error}"
1506 )))
1507 })
1508}
1509
1510fn parse_json_arguments<T>(arguments: &str) -> Result<T>
1511where
1512 T: serde::de::DeserializeOwned,
1513{
1514 serde_json::from_str(arguments).map_err(|error| {
1515 Error::Serialization(crate::SerializationError::new(format!(
1516 "工具参数 JSON 解析失败: {error}"
1517 )))
1518 })
1519}
1520
1521handle!(
1522 CompletionsResource
1524);
1525handle!(
1526 ChatResource
1528);
1529handle!(
1530 ChatCompletionsResource
1532);
1533handle!(
1534 ChatCompletionMessagesResource
1536);
1537handle!(
1538 EmbeddingsResource
1540);
1541handle!(
1542 FilesResource
1544);
1545handle!(
1546 ImagesResource
1548);
1549handle!(
1550 AudioResource
1552);
1553handle!(
1554 AudioSpeechResource
1556);
1557handle!(
1558 AudioTranscriptionsResource
1560);
1561handle!(
1562 AudioTranslationsResource
1564);
1565handle!(
1566 ModerationsResource
1568);
1569handle!(
1570 ModelsResource
1572);
1573handle!(
1574 FineTuningResource
1576);
1577handle!(
1578 FineTuningJobsResource
1580);
1581handle!(
1582 FineTuningJobCheckpointsResource
1584);
1585handle!(
1586 FineTuningCheckpointPermissionsResource
1588);
1589handle!(
1590 FineTuningAlphaResource
1592);
1593handle!(
1594 FineTuningAlphaGradersResource
1596);
1597handle!(
1598 GradersResource
1600);
1601handle!(
1602 VectorStoresResource
1604);
1605handle!(
1606 VectorStoreFilesResource
1608);
1609handle!(
1610 VectorStoreFileBatchesResource
1612);
1613handle!(
1614 BatchesResource
1616);
1617handle!(
1618 UploadsResource
1620);
1621handle!(
1622 UploadPartsResource
1624);
1625handle!(
1626 ResponsesResource
1628);
1629handle!(
1630 ResponseInputItemsResource
1632);
1633handle!(
1634 ResponseInputTokensResource
1636);
1637handle!(
1638 RealtimeResource
1640);
1641handle!(
1642 RealtimeClientSecretsResource
1644);
1645handle!(
1646 RealtimeCallsResource
1648);
1649handle!(
1650 ConversationsResource
1652);
1653handle!(
1654 ConversationItemsResource
1656);
1657handle!(
1658 EvalsResource
1660);
1661handle!(
1662 EvalRunsResource
1664);
1665handle!(
1666 EvalRunOutputItemsResource
1668);
1669handle!(
1670 ContainersResource
1672);
1673handle!(
1674 ContainerFilesResource
1676);
1677handle!(
1678 ContainerFilesContentResource
1680);
1681handle!(
1682 SkillsResource
1684);
1685handle!(
1686 SkillsContentResource
1688);
1689handle!(
1690 SkillVersionsResource
1692);
1693handle!(
1694 SkillVersionsContentResource
1696);
1697handle!(
1698 VideosResource
1700);
1701handle!(
1702 WebhooksResource
1704);
1705handle!(
1706 BetaResource
1708);
1709handle!(
1710 BetaAssistantsResource
1712);
1713handle!(
1714 BetaThreadsResource
1716);
1717handle!(
1718 BetaThreadMessagesResource
1720);
1721handle!(
1722 BetaThreadRunsResource
1724);
1725handle!(
1726 BetaThreadRunStepsResource
1728);
1729handle!(
1730 BetaChatkitResource
1732);
1733handle!(
1734 BetaChatkitSessionsResource
1736);
1737handle!(
1738 BetaChatkitThreadsResource
1740);
1741handle!(
1742 BetaRealtimeResource
1744);
1745handle!(
1746 BetaRealtimeSessionsResource
1748);
1749handle!(
1750 BetaRealtimeTranscriptionSessionsResource
1752);