1mod admin;
4mod audio;
5mod batches;
6mod beta;
7mod chat;
8mod common;
9mod containers;
10mod conversations;
11mod core;
12mod evals;
13mod files;
14mod fine_tuning;
15mod images;
16mod longtail;
17mod responses;
18mod skills;
19mod uploads;
20mod vector_stores;
21mod videos;
22mod webhooks;
23
24use std::collections::BTreeMap;
25
26use serde::{Deserialize, Serialize};
27use serde_json::Value;
28
29use crate::Client;
30use crate::error::{Error, Result};
31#[cfg(feature = "tool-runner")]
32use crate::helpers::ToolDefinition;
33use crate::json_payload::JsonPayload;
34
35pub use beta::{
36 BetaAssistant, BetaAssistantTool, BetaRealtimeSession, BetaRealtimeTranscriptionSession,
37 BetaThread, BetaThreadMessage, BetaThreadMessageContent, BetaThreadRun,
38 BetaThreadRunIncompleteDetails, BetaThreadRunLastError, BetaThreadRunRequiredAction,
39 BetaThreadRunRequiredActionFunction, BetaThreadRunRequiredActionFunctionToolCall,
40 BetaThreadRunRequiredActionSubmitToolOutputs, BetaThreadRunStep, BetaThreadRunStepDetails,
41 BetaThreadRunTool, BetaThreadRunUsage, BetaThreadToolResources, ChatKitConfiguration,
42 ChatKitRateLimits, ChatKitSession, ChatKitThread, ChatKitThreadContent, ChatKitThreadItem,
43 ChatKitThreadStatus, ChatKitWorkflow,
44};
45#[cfg(feature = "structured-output")]
46pub use chat::ChatCompletionParseRequestBuilder;
47pub use chat::{
48 AssistantStreamRequestBuilder, ChatCompletionCreateRequestBuilder, ChatCompletionStoreMessage,
49 ChatCompletionStreamRequestBuilder,
50};
51#[cfg(feature = "tool-runner")]
52pub use chat::{
53 ChatCompletionRunToolsRequestBuilder, ChatCompletionRunner, ChatCompletionStreamingRunner,
54 ChatCompletionToolResult,
55};
56pub use common::{
57 BytesRequestBuilder, JsonRequestBuilder, ListRequestBuilder, NoContentRequestBuilder,
58};
59pub(crate) use common::{
60 TypedJsonRequestState, encode_path_segment, metadata_is_empty, value_from,
61};
62pub use core::{
63 Completion, CompletionChoice, CompletionLogProbs, CompletionUsage,
64 CompletionUsageCompletionTokensDetails, CompletionUsagePromptTokensDetails,
65 ModerationCreateResponse, ModerationResult,
66};
67pub use fine_tuning::{
68 GraderModel, GraderModelCatalog, GraderRunErrors, GraderRunMetadata, GraderRunResponse,
69 GraderValidateResponse,
70};
71pub use longtail::{
72 AudioSpeechCreateParams, AudioSpeechRequestBuilder, AudioTranscription,
73 AudioTranscriptionRequestBuilder, AudioTranscriptionSegment, AudioTranscriptionSegmentId,
74 AudioTranscriptionWord, AudioTranslation, AudioTranslationRequestBuilder, Batch,
75 BatchCreateParams, BatchCreateRequestBuilder, BatchError, BatchErrors, BatchRequestCounts,
76 BatchUsage, BatchUsageInputTokensDetails, BatchUsageOutputTokensDetails, Container,
77 ContainerCreateParams, ContainerExpiresAfter, ContainerFile, ContainerFileCreateParams,
78 Conversation, ConversationContentPart, ConversationCreateParams, ConversationInputItem,
79 ConversationItem, ConversationItemCreateParams, ConversationUpdateParams, Eval,
80 EvalCreateParams, EvalDataSourceConfig, EvalOutput, EvalOutputItem, EvalRun,
81 EvalRunCreateParams, EvalRunInput, EvalTestingCriterion, EvalUpdateParams,
82 FineTuningCheckpoint, FineTuningCheckpointPermission, FineTuningHyperparameterValue,
83 FineTuningJob, FineTuningJobCreateParams, FineTuningJobCreateRequestBuilder,
84 FineTuningJobError, FineTuningJobEvent, FineTuningJobHyperparameters, FineTuningJobIntegration,
85 FineTuningMetrics, FineTuningWandbIntegration, ImageData, ImageGenerateParams,
86 ImageGenerateRequestBuilder, ImageGenerationResponse, Skill, SkillCreateParams,
87 SkillUpdateParams, SkillVersion, SkillVersionContent, SkillVersionCreateParams, Video,
88 VideoCharacter, VideoCharacterCreateParams, VideoCreateParams,
89};
90#[cfg(feature = "realtime")]
91pub use responses::RealtimeSocketRequestBuilder;
92#[cfg(feature = "structured-output")]
93pub use responses::ResponseParseRequestBuilder;
94#[cfg(feature = "responses-ws")]
95pub use responses::ResponsesSocketRequestBuilder;
96pub use responses::{
97 RealtimeClientSecretCreateResponse, RealtimeSessionClientSecret, ResponseCreateRequestBuilder,
98 ResponseStreamRequestBuilder,
99};
100pub use uploads::UploadPart;
101pub use vector_stores::{
102 VectorStore, VectorStoreAttributeValue, VectorStoreAttributes, VectorStoreExpiresAfter,
103 VectorStoreFile, VectorStoreFileBatch, VectorStoreFileChunkingStrategy, VectorStoreFileContent,
104 VectorStoreFileCounts, VectorStoreFileLastError, VectorStoreMetadata, VectorStoreSearchContent,
105 VectorStoreSearchResponse, VectorStoreSearchResult, VectorStoreStaticFileChunkingStrategy,
106};
107
108macro_rules! json_payload_wrapper {
109 ($(#[$meta:meta])* $name:ident) => {
110 $(#[$meta])*
111 #[derive(Debug, Clone, Serialize, Deserialize)]
112 #[serde(transparent)]
113 pub struct $name(Value);
114
115 impl Default for $name {
116 fn default() -> Self {
117 Self(Value::Null)
118 }
119 }
120
121 impl From<Value> for $name {
122 fn from(value: Value) -> Self {
123 Self(value)
124 }
125 }
126
127 impl From<$name> for Value {
128 fn from(value: $name) -> Self {
129 value.0
130 }
131 }
132
133 impl $name {
134 pub fn as_raw(&self) -> &Value {
136 &self.0
137 }
138
139 pub fn into_raw(self) -> Value {
141 self.0
142 }
143
144 pub fn kind(&self) -> Option<&str> {
146 self.0.get("type").and_then(Value::as_str)
147 }
148 }
149 };
150}
151
152macro_rules! handle {
153 ($(#[$meta:meta])* $name:ident) => {
154 $(#[$meta])*
155 #[derive(Debug, Clone)]
156 pub struct $name {
157 client: Client,
158 }
159
160 impl $name {
161 pub(crate) fn new(client: Client) -> Self {
162 Self { client }
163 }
164 }
165 };
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize, Default)]
170pub struct DeleteResponse {
171 pub id: Option<String>,
173 #[serde(default)]
175 pub deleted: bool,
176 pub object: Option<String>,
178 #[serde(flatten)]
180 pub extra: BTreeMap<String, Value>,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize, Default)]
185pub struct Model {
186 pub id: String,
188 #[serde(default)]
190 pub object: String,
191 pub owned_by: Option<String>,
193 #[serde(flatten)]
195 pub extra: BTreeMap<String, Value>,
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize, Default)]
200pub struct FileObject {
201 pub id: String,
203 #[serde(default)]
205 pub object: String,
206 pub filename: Option<String>,
208 pub purpose: Option<String>,
210 pub bytes: Option<u64>,
212 #[serde(flatten)]
214 pub extra: BTreeMap<String, Value>,
215}
216
217#[derive(Debug, Clone, Serialize, Deserialize, Default)]
219pub struct UploadObject {
220 pub id: String,
222 #[serde(default)]
224 pub object: String,
225 pub status: Option<String>,
227 #[serde(flatten)]
229 pub extra: BTreeMap<String, Value>,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize, Default)]
234pub struct EmbeddingResponse {
235 #[serde(default)]
237 pub object: String,
238 #[serde(default)]
240 pub data: Vec<EmbeddingData>,
241 pub usage: Option<EmbeddingUsage>,
243 #[serde(flatten)]
245 pub extra: BTreeMap<String, Value>,
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize, Default)]
250pub struct EmbeddingData {
251 #[serde(default)]
253 pub embedding: Vec<f64>,
254 pub index: Option<u32>,
256 #[serde(default)]
258 pub object: String,
259 #[serde(flatten)]
261 pub extra: BTreeMap<String, Value>,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize, Default)]
266pub struct EmbeddingUsage {
267 #[serde(default)]
269 pub prompt_tokens: u64,
270 #[serde(default)]
272 pub total_tokens: u64,
273 #[serde(flatten)]
275 pub extra: BTreeMap<String, Value>,
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize, Default)]
280pub struct InputTokenCount {
281 pub total_tokens: u64,
283 #[serde(flatten)]
285 pub extra: BTreeMap<String, Value>,
286}
287
288json_payload_wrapper!(
289 ChatCompletionStoreContentPart
291);
292json_payload_wrapper!(
293 ChatReasoningDetail
295);
296json_payload_wrapper!(
297 ChatMessageContentPart
299);
300json_payload_wrapper!(
301 ChatToolChoice
303);
304json_payload_wrapper!(
305 ResponseInputPayload
307);
308json_payload_wrapper!(
309 ResponseInputItemPayload
311);
312json_payload_wrapper!(
313 RealtimeSessionPayload
315);
316json_payload_wrapper!(
317 ResponseOutputItemRaw
319);
320json_payload_wrapper!(
321 ResponseOutputContentPartRaw
323);
324
325#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
327#[serde(rename_all = "snake_case")]
328pub enum ChatToolChoiceMode {
329 None,
331 Auto,
333 Required,
335}
336
337impl From<ChatToolChoiceMode> for ChatToolChoice {
338 fn from(mode: ChatToolChoiceMode) -> Self {
339 let value = match mode {
340 ChatToolChoiceMode::None => Value::String("none".into()),
341 ChatToolChoiceMode::Auto => Value::String("auto".into()),
342 ChatToolChoiceMode::Required => Value::String("required".into()),
343 };
344 Self::from(value)
345 }
346}
347
348impl From<String> for ResponseInputPayload {
349 fn from(value: String) -> Self {
350 Self::from(Value::String(value))
351 }
352}
353
354impl From<&str> for ResponseInputPayload {
355 fn from(value: &str) -> Self {
356 Self::from(Value::String(value.into()))
357 }
358}
359
360impl From<Vec<ResponseInputItemPayload>> for ResponseInputPayload {
361 fn from(items: Vec<ResponseInputItemPayload>) -> Self {
362 Self::from(Value::Array(items.into_iter().map(Value::from).collect()))
363 }
364}
365
366impl ChatToolChoice {
367 pub fn none() -> Self {
369 ChatToolChoiceMode::None.into()
370 }
371
372 pub fn auto() -> Self {
374 ChatToolChoiceMode::Auto.into()
375 }
376
377 pub fn required() -> Self {
379 ChatToolChoiceMode::Required.into()
380 }
381
382 pub fn function(name: impl Into<String>) -> Self {
384 serde_json::json!({
385 "type": "function",
386 "function": {
387 "name": name.into(),
388 },
389 })
390 .into()
391 }
392
393 pub fn custom(name: impl Into<String>) -> Self {
395 serde_json::json!({
396 "type": "custom",
397 "custom": {
398 "name": name.into(),
399 },
400 })
401 .into()
402 }
403
404 pub fn mode_name(&self) -> Option<&str> {
406 self.0.as_str()
407 }
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize, Default)]
412pub struct ChatCompletionFunctionCall {
413 pub name: String,
415 #[serde(default)]
417 pub arguments: String,
418}
419
420#[derive(Debug, Clone, Serialize, Deserialize, Default)]
422pub struct ChatCompletionToolCall {
423 pub id: String,
425 #[serde(rename = "type", default = "default_function_type")]
427 pub call_type: String,
428 pub function: ChatCompletionFunctionCall,
430 #[serde(flatten)]
432 pub extra: BTreeMap<String, Value>,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
437pub struct ChatCompletionTokenTopLogprob {
438 #[serde(default)]
440 pub token: String,
441 pub bytes: Option<Vec<u8>>,
443 #[serde(default)]
445 pub logprob: f64,
446 #[serde(flatten)]
448 pub extra: BTreeMap<String, Value>,
449}
450
451#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
453pub struct ChatCompletionTokenLogprob {
454 #[serde(default)]
456 pub token: String,
457 pub bytes: Option<Vec<u8>>,
459 #[serde(default)]
461 pub logprob: f64,
462 #[serde(default)]
464 pub top_logprobs: Vec<ChatCompletionTokenTopLogprob>,
465 #[serde(flatten)]
467 pub extra: BTreeMap<String, Value>,
468}
469
470#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
472pub struct ChatCompletionChoiceLogprobs {
473 #[serde(default, skip_serializing_if = "Vec::is_empty")]
475 pub content: Vec<ChatCompletionTokenLogprob>,
476 #[serde(default, skip_serializing_if = "Vec::is_empty")]
478 pub refusal: Vec<ChatCompletionTokenLogprob>,
479 #[serde(flatten)]
481 pub extra: BTreeMap<String, Value>,
482}
483
484impl ChatCompletionChoiceLogprobs {
485 pub fn values(&self, field_name: &str) -> Option<&[ChatCompletionTokenLogprob]> {
487 match field_name {
488 "content" if !self.content.is_empty() => Some(&self.content),
489 "refusal" if !self.refusal.is_empty() => Some(&self.refusal),
490 _ => None,
491 }
492 }
493}
494
495#[derive(Debug, Clone, Serialize, Deserialize, Default)]
497pub struct ChatCompletionFunctionCallDelta {
498 pub name: Option<String>,
500 pub arguments: Option<String>,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize, Default)]
506pub struct ChatCompletionToolCallDelta {
507 pub index: Option<u32>,
509 pub id: Option<String>,
511 #[serde(rename = "type")]
513 pub call_type: Option<String>,
514 pub function: Option<ChatCompletionFunctionCallDelta>,
516}
517
518#[derive(Debug, Clone, Serialize, Deserialize, Default)]
520pub struct ChatCompletionMessage {
521 pub role: String,
523 #[serde(skip_serializing_if = "Option::is_none")]
525 pub content: Option<String>,
526 #[serde(skip_serializing_if = "Option::is_none")]
528 pub name: Option<String>,
529 #[serde(skip_serializing_if = "Option::is_none")]
531 pub tool_call_id: Option<String>,
532 #[serde(default, skip_serializing_if = "Vec::is_empty")]
534 pub tool_calls: Vec<ChatCompletionToolCall>,
535 #[serde(skip_serializing_if = "Option::is_none")]
537 pub refusal: Option<String>,
538 #[serde(skip_serializing_if = "Option::is_none")]
540 pub reasoning_content: Option<String>,
541 #[serde(default, skip_serializing_if = "Vec::is_empty")]
543 pub reasoning_details: Vec<ChatReasoningDetail>,
544 #[serde(flatten)]
546 pub extra: BTreeMap<String, Value>,
547}
548
549impl ChatCompletionMessage {
550 pub fn system(content: impl Into<String>) -> Self {
552 Self {
553 role: "system".into(),
554 content: Some(content.into()),
555 ..Self::default()
556 }
557 }
558
559 pub fn user(content: impl Into<String>) -> Self {
561 Self {
562 role: "user".into(),
563 content: Some(content.into()),
564 ..Self::default()
565 }
566 }
567
568 pub fn user_content_parts(parts: Vec<ChatMessageContentPart>) -> Self {
570 Self::with_content_parts("user", parts)
571 }
572
573 pub fn with_content_parts(role: impl Into<String>, parts: Vec<ChatMessageContentPart>) -> Self {
575 let mut extra = BTreeMap::new();
576 extra.insert(
577 "content".into(),
578 Value::Array(parts.into_iter().map(Value::from).collect()),
579 );
580 Self {
581 role: role.into(),
582 content: None,
583 extra,
584 ..Self::default()
585 }
586 }
587
588 pub fn content_text(text: impl Into<String>) -> ChatMessageContentPart {
590 serde_json::json!({
591 "type": "text",
592 "text": text.into(),
593 })
594 .into()
595 }
596
597 pub fn content_image_url(url: impl Into<String>) -> ChatMessageContentPart {
599 serde_json::json!({
600 "type": "image_url",
601 "image_url": {
602 "url": url.into(),
603 },
604 })
605 .into()
606 }
607
608 pub fn content_video_url(url: impl Into<String>) -> ChatMessageContentPart {
610 serde_json::json!({
611 "type": "video_url",
612 "video_url": {
613 "url": url.into(),
614 },
615 })
616 .into()
617 }
618
619 pub fn content_file(file_id: impl Into<String>) -> ChatMessageContentPart {
621 serde_json::json!({
622 "type": "file",
623 "file": {
624 "file_id": file_id.into(),
625 },
626 })
627 .into()
628 }
629
630 pub fn assistant(content: impl Into<String>) -> Self {
632 Self {
633 role: "assistant".into(),
634 content: Some(content.into()),
635 ..Self::default()
636 }
637 }
638
639 pub fn tool(tool_call_id: impl Into<String>, content: impl Into<String>) -> Self {
641 Self {
642 role: "tool".into(),
643 content: Some(content.into()),
644 tool_call_id: Some(tool_call_id.into()),
645 ..Self::default()
646 }
647 }
648
649 pub fn parse_content<T>(&self) -> Result<Option<T>>
655 where
656 T: serde::de::DeserializeOwned,
657 {
658 self.content
659 .as_deref()
660 .map(parse_jsonish_payload)
661 .transpose()
662 }
663
664 pub fn parse_tool_arguments<T>(&self) -> Result<Option<T>>
670 where
671 T: serde::de::DeserializeOwned,
672 {
673 self.tool_calls
674 .first()
675 .map(|tool_call| parse_json_arguments(&tool_call.function.arguments))
676 .transpose()
677 }
678
679 pub fn parse_tool_arguments_by_id<T>(&self, tool_call_id: &str) -> Result<Option<T>>
685 where
686 T: serde::de::DeserializeOwned,
687 {
688 self.tool_calls
689 .iter()
690 .find(|tool_call| tool_call.id == tool_call_id)
691 .map(|tool_call| parse_json_arguments(&tool_call.function.arguments))
692 .transpose()
693 }
694}
695
696#[derive(Debug, Clone, Serialize, Deserialize, Default)]
698pub struct ChatCompletionChoice {
699 pub index: u32,
701 pub finish_reason: Option<String>,
703 pub message: ChatCompletionMessage,
705 pub logprobs: Option<ChatCompletionChoiceLogprobs>,
707 #[serde(flatten)]
709 pub extra: BTreeMap<String, Value>,
710}
711
712#[derive(Debug, Clone, Serialize, Deserialize, Default)]
714pub struct ChatCompletion {
715 pub id: String,
717 #[serde(default)]
719 pub object: String,
720 pub created: Option<i64>,
722 #[serde(default)]
724 pub model: String,
725 #[serde(default)]
727 pub choices: Vec<ChatCompletionChoice>,
728 pub usage: Option<CompletionUsage>,
730 #[serde(flatten)]
732 pub extra: BTreeMap<String, Value>,
733}
734
735impl ChatCompletion {
736 pub fn ensure_not_truncated(&self) -> Result<&Self> {
742 for choice in &self.choices {
743 match choice.finish_reason.as_deref() {
744 Some("length") => return Err(crate::LengthFinishReasonError.into()),
745 Some("content_filter") => return Err(crate::ContentFilterFinishReasonError.into()),
746 _ => {}
747 }
748 }
749 Ok(self)
750 }
751}
752
753#[derive(Debug, Clone, Serialize, Deserialize, Default)]
755pub struct ChatCompletionChunkDelta {
756 pub role: Option<String>,
758 pub content: Option<String>,
760 pub refusal: Option<String>,
762 pub reasoning_content: Option<String>,
764 #[serde(default)]
766 pub reasoning_details: Vec<ChatReasoningDetail>,
767 #[serde(default)]
769 pub tool_calls: Vec<ChatCompletionToolCallDelta>,
770 #[serde(flatten)]
772 pub extra: BTreeMap<String, Value>,
773}
774
775#[derive(Debug, Clone, Serialize, Deserialize, Default)]
777pub struct ChatCompletionChunkChoice {
778 pub index: u32,
780 pub delta: ChatCompletionChunkDelta,
782 pub finish_reason: Option<String>,
784 pub logprobs: Option<ChatCompletionChoiceLogprobs>,
786 #[serde(flatten)]
788 pub extra: BTreeMap<String, Value>,
789}
790
791#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
793pub struct ChatContentDeltaEvent {
794 pub choice_index: u32,
796 pub delta: String,
798}
799
800#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
802pub struct ChatRefusalDeltaEvent {
803 pub choice_index: u32,
805 pub delta: String,
807}
808
809#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
811pub struct ChatToolArgumentsDeltaEvent {
812 pub choice_index: u32,
814 pub tool_call_index: u32,
816 pub name: Option<String>,
818 pub delta: String,
820}
821
822#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
824pub struct ChatLogProbsDeltaEvent {
825 pub choice_index: u32,
827 pub values: Vec<ChatCompletionTokenLogprob>,
829}
830
831#[derive(Debug, Clone, Serialize, Deserialize, Default)]
833pub struct ChatCompletionChunk {
834 pub id: String,
836 #[serde(default)]
838 pub object: String,
839 pub created: Option<i64>,
841 #[serde(default)]
843 pub model: String,
844 #[serde(default)]
846 pub choices: Vec<ChatCompletionChunkChoice>,
847 #[serde(flatten)]
849 pub extra: BTreeMap<String, Value>,
850}
851
852impl ChatCompletionChunk {
853 pub fn content_deltas(&self) -> Vec<ChatContentDeltaEvent> {
855 self.choices
856 .iter()
857 .filter_map(|choice| {
858 choice
859 .delta
860 .content
861 .as_ref()
862 .map(|delta| ChatContentDeltaEvent {
863 choice_index: choice.index,
864 delta: delta.clone(),
865 })
866 })
867 .collect()
868 }
869
870 pub fn refusal_deltas(&self) -> Vec<ChatRefusalDeltaEvent> {
872 self.choices
873 .iter()
874 .filter_map(|choice| {
875 choice
876 .delta
877 .refusal
878 .as_ref()
879 .map(|delta| ChatRefusalDeltaEvent {
880 choice_index: choice.index,
881 delta: delta.clone(),
882 })
883 })
884 .collect()
885 }
886
887 pub fn tool_argument_deltas(&self) -> Vec<ChatToolArgumentsDeltaEvent> {
889 self.choices
890 .iter()
891 .flat_map(|choice| {
892 choice.delta.tool_calls.iter().filter_map(|tool_call| {
893 let delta = tool_call.function.as_ref()?.arguments.clone()?;
894 Some(ChatToolArgumentsDeltaEvent {
895 choice_index: choice.index,
896 tool_call_index: tool_call.index.unwrap_or_default(),
897 name: tool_call
898 .function
899 .as_ref()
900 .and_then(|function| function.name.clone()),
901 delta,
902 })
903 })
904 })
905 .collect()
906 }
907
908 pub fn logprobs_content_deltas(&self) -> Vec<ChatLogProbsDeltaEvent> {
910 extract_logprobs(self, "content")
911 }
912
913 pub fn logprobs_refusal_deltas(&self) -> Vec<ChatLogProbsDeltaEvent> {
915 extract_logprobs(self, "refusal")
916 }
917}
918
919fn extract_logprobs(chunk: &ChatCompletionChunk, field_name: &str) -> Vec<ChatLogProbsDeltaEvent> {
920 chunk
921 .choices
922 .iter()
923 .filter_map(|choice| {
924 let values = choice
925 .logprobs
926 .as_ref()
927 .and_then(|logprobs| logprobs.values(field_name))?
928 .to_vec();
929 Some(ChatLogProbsDeltaEvent {
930 choice_index: choice.index,
931 values,
932 })
933 })
934 .collect()
935}
936
937#[derive(Debug, Clone, Serialize, Deserialize)]
939pub struct ChatToolDefinition {
940 #[serde(rename = "type")]
942 pub tool_type: String,
943 pub function: ChatToolFunction,
945}
946
947impl ChatToolDefinition {
948 #[cfg(feature = "tool-runner")]
949 fn from_tool(tool: &ToolDefinition) -> Self {
950 Self {
951 tool_type: "function".into(),
952 function: ChatToolFunction {
953 name: tool.name.clone(),
954 description: tool.description.clone(),
955 parameters: tool.parameters.clone(),
956 },
957 }
958 }
959
960 fn as_response_tool_value(&self) -> Value {
962 serde_json::json!({
963 "type": self.tool_type,
964 "name": self.function.name,
965 "description": self.function.description,
966 "parameters": self.function.parameters,
967 })
968 }
969}
970
971#[derive(Debug, Clone, Serialize, Deserialize)]
973pub struct ChatToolFunction {
974 pub name: String,
976 pub description: Option<String>,
978 pub parameters: JsonPayload,
980}
981
982#[derive(Debug, Clone, Serialize, Deserialize, Default)]
984pub struct ChatCompletionCreateParams {
985 #[serde(skip_serializing_if = "Option::is_none")]
987 pub model: Option<String>,
988 #[serde(default, skip_serializing_if = "Vec::is_empty")]
990 pub messages: Vec<ChatCompletionMessage>,
991 #[serde(skip_serializing_if = "Option::is_none")]
993 pub temperature: Option<f32>,
994 #[serde(skip_serializing_if = "Option::is_none")]
996 pub n: Option<u32>,
997 #[serde(skip_serializing_if = "Option::is_none")]
999 pub max_tokens: Option<u32>,
1000 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1002 pub tools: Vec<ChatToolDefinition>,
1003 #[serde(skip_serializing_if = "Option::is_none")]
1005 pub tool_choice: Option<ChatToolChoice>,
1006 #[serde(skip_serializing_if = "Option::is_none")]
1008 pub stream: Option<bool>,
1009}
1010
1011#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1013pub struct Response {
1014 pub id: String,
1016 pub created_at: Option<u64>,
1018 #[serde(default)]
1020 pub object: String,
1021 pub model: Option<String>,
1023 pub status: Option<String>,
1025 pub error: Option<ResponseError>,
1027 pub incomplete_details: Option<ResponseIncompleteDetails>,
1029 pub metadata: Option<BTreeMap<String, String>>,
1031 #[serde(default)]
1033 pub output: Vec<ResponseOutputItem>,
1034 pub usage: Option<ResponseUsage>,
1036 #[serde(flatten)]
1038 pub extra: BTreeMap<String, Value>,
1039}
1040
1041impl Response {
1042 pub fn output_text(&self) -> Option<String> {
1044 for item in &self.output {
1045 if let Some(text) = item.output_text() {
1046 return Some(text.to_owned());
1047 }
1048 }
1049
1050 self.extra
1051 .get("output_text")
1052 .and_then(Value::as_str)
1053 .map(str::to_owned)
1054 }
1055}
1056
1057#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1059pub struct ResponseError {
1060 pub code: Option<String>,
1062 pub message: Option<String>,
1064 #[serde(flatten)]
1066 pub extra: BTreeMap<String, Value>,
1067}
1068
1069#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1071pub struct ResponseIncompleteDetails {
1072 pub reason: Option<String>,
1074 #[serde(flatten)]
1076 pub extra: BTreeMap<String, Value>,
1077}
1078
1079#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1081pub struct ResponseUsage {
1082 #[serde(default)]
1084 pub input_tokens: u64,
1085 pub input_tokens_details: Option<ResponseInputTokensDetails>,
1087 #[serde(default)]
1089 pub output_tokens: u64,
1090 pub output_tokens_details: Option<ResponseOutputTokensDetails>,
1092 #[serde(default)]
1094 pub total_tokens: u64,
1095 #[serde(flatten)]
1097 pub extra: BTreeMap<String, Value>,
1098}
1099
1100#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1102pub struct ResponseInputTokensDetails {
1103 pub cached_tokens: Option<u64>,
1105 #[serde(flatten)]
1107 pub extra: BTreeMap<String, Value>,
1108}
1109
1110#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1112pub struct ResponseOutputTokensDetails {
1113 pub reasoning_tokens: Option<u64>,
1115 #[serde(flatten)]
1117 pub extra: BTreeMap<String, Value>,
1118}
1119
1120#[derive(Debug, Clone, Serialize, Deserialize)]
1122#[serde(untagged)]
1123pub enum ResponseOutputItem {
1124 Known(KnownResponseOutputItem),
1126 Raw(ResponseOutputItemRaw),
1128}
1129
1130impl Default for ResponseOutputItem {
1131 fn default() -> Self {
1132 Self::Raw(ResponseOutputItemRaw::default())
1133 }
1134}
1135
1136impl ResponseOutputItem {
1137 pub fn as_message(&self) -> Option<&ResponseOutputMessage> {
1139 match self {
1140 Self::Known(KnownResponseOutputItem::Message(message)) => Some(message),
1141 _ => None,
1142 }
1143 }
1144
1145 pub fn as_function_call(&self) -> Option<&ResponseFunctionToolCall> {
1147 match self {
1148 Self::Known(KnownResponseOutputItem::FunctionCall(call)) => Some(call),
1149 _ => None,
1150 }
1151 }
1152
1153 pub fn as_raw(&self) -> Option<&Value> {
1155 match self {
1156 Self::Raw(value) => Some(value.as_raw()),
1157 _ => None,
1158 }
1159 }
1160
1161 pub fn output_text(&self) -> Option<&str> {
1163 match self {
1164 Self::Known(KnownResponseOutputItem::OutputText(text)) => Some(text.text.as_str()),
1165 Self::Known(KnownResponseOutputItem::Message(message)) => message
1166 .content
1167 .iter()
1168 .find_map(ResponseOutputContentPart::text),
1169 Self::Raw(value) => {
1170 let value = value.as_raw();
1171 if let Some(text) = value.get("text").and_then(Value::as_str) {
1172 return Some(text);
1173 }
1174 value
1175 .get("content")
1176 .and_then(Value::as_array)
1177 .and_then(|content| {
1178 content
1179 .iter()
1180 .find_map(|item| item.get("text").and_then(Value::as_str))
1181 })
1182 }
1183 _ => None,
1184 }
1185 }
1186}
1187
1188#[derive(Debug, Clone, Serialize, Deserialize)]
1190#[serde(tag = "type", rename_all = "snake_case")]
1191pub enum KnownResponseOutputItem {
1192 Message(ResponseOutputMessage),
1194 FunctionCall(ResponseFunctionToolCall),
1196 OutputText(ResponseOutputText),
1198 Refusal(ResponseOutputRefusal),
1200}
1201
1202#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1204pub struct ResponseOutputMessage {
1205 pub id: String,
1207 #[serde(default)]
1209 pub content: Vec<ResponseOutputContentPart>,
1210 pub role: Option<String>,
1212 pub status: Option<String>,
1214 pub phase: Option<String>,
1216 #[serde(flatten)]
1218 pub extra: BTreeMap<String, Value>,
1219}
1220
1221#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1223pub struct ResponseFunctionToolCall {
1224 pub id: String,
1226 pub call_id: Option<String>,
1228 pub name: Option<String>,
1230 #[serde(default)]
1232 pub arguments: String,
1233 pub status: Option<String>,
1235 #[serde(flatten)]
1237 pub extra: BTreeMap<String, Value>,
1238}
1239
1240#[derive(Debug, Clone, Serialize, Deserialize)]
1242#[serde(untagged)]
1243pub enum ResponseOutputContentPart {
1244 Known(KnownResponseOutputContentPart),
1246 Raw(ResponseOutputContentPartRaw),
1248}
1249
1250impl Default for ResponseOutputContentPart {
1251 fn default() -> Self {
1252 Self::Raw(ResponseOutputContentPartRaw::default())
1253 }
1254}
1255
1256impl ResponseOutputContentPart {
1257 pub fn as_output_text(&self) -> Option<&ResponseOutputText> {
1259 match self {
1260 Self::Known(KnownResponseOutputContentPart::OutputText(text)) => Some(text),
1261 _ => None,
1262 }
1263 }
1264
1265 pub fn text(&self) -> Option<&str> {
1267 match self {
1268 Self::Known(KnownResponseOutputContentPart::OutputText(text)) => {
1269 Some(text.text.as_str())
1270 }
1271 Self::Raw(value) => value.as_raw().get("text").and_then(Value::as_str),
1272 _ => None,
1273 }
1274 }
1275}
1276
1277#[derive(Debug, Clone, Serialize, Deserialize)]
1279#[serde(tag = "type", rename_all = "snake_case")]
1280pub enum KnownResponseOutputContentPart {
1281 OutputText(ResponseOutputText),
1283 Refusal(ResponseOutputRefusal),
1285}
1286
1287#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1289pub struct ResponseOutputTextFileCitation {
1290 pub file_id: String,
1292 pub filename: String,
1294 pub index: u64,
1296 #[serde(flatten)]
1298 pub extra: BTreeMap<String, Value>,
1299}
1300
1301#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1303pub struct ResponseOutputTextUrlCitation {
1304 pub end_index: u64,
1306 pub start_index: u64,
1308 pub title: String,
1310 pub url: String,
1312 #[serde(flatten)]
1314 pub extra: BTreeMap<String, Value>,
1315}
1316
1317#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1319pub struct ResponseOutputTextContainerFileCitation {
1320 pub container_id: String,
1322 pub end_index: u64,
1324 pub file_id: String,
1326 pub filename: String,
1328 pub start_index: u64,
1330 #[serde(flatten)]
1332 pub extra: BTreeMap<String, Value>,
1333}
1334
1335#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
1337pub struct ResponseOutputTextFilePath {
1338 pub file_id: String,
1340 pub index: u64,
1342 #[serde(flatten)]
1344 pub extra: BTreeMap<String, Value>,
1345}
1346
1347#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1349#[serde(tag = "type", rename_all = "snake_case")]
1350pub enum KnownResponseOutputTextAnnotation {
1351 FileCitation(ResponseOutputTextFileCitation),
1353 UrlCitation(ResponseOutputTextUrlCitation),
1355 ContainerFileCitation(ResponseOutputTextContainerFileCitation),
1357 FilePath(ResponseOutputTextFilePath),
1359}
1360
1361#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1363pub struct ResponseOutputTextAnnotationUnknown {
1364 #[serde(rename = "type")]
1366 pub annotation_type: Option<String>,
1367 #[serde(flatten)]
1369 pub extra: BTreeMap<String, Value>,
1370}
1371
1372#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1374#[serde(untagged)]
1375pub enum ResponseOutputTextAnnotation {
1376 Known(KnownResponseOutputTextAnnotation),
1378 Unknown(ResponseOutputTextAnnotationUnknown),
1380}
1381
1382impl Default for ResponseOutputTextAnnotation {
1383 fn default() -> Self {
1384 Self::Unknown(ResponseOutputTextAnnotationUnknown::default())
1385 }
1386}
1387
1388impl ResponseOutputTextAnnotation {
1389 pub fn kind(&self) -> Option<&str> {
1391 match self {
1392 Self::Known(KnownResponseOutputTextAnnotation::FileCitation(_)) => {
1393 Some("file_citation")
1394 }
1395 Self::Known(KnownResponseOutputTextAnnotation::UrlCitation(_)) => Some("url_citation"),
1396 Self::Known(KnownResponseOutputTextAnnotation::ContainerFileCitation(_)) => {
1397 Some("container_file_citation")
1398 }
1399 Self::Known(KnownResponseOutputTextAnnotation::FilePath(_)) => Some("file_path"),
1400 Self::Unknown(annotation) => annotation.annotation_type.as_deref(),
1401 }
1402 }
1403}
1404
1405#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1407pub struct ResponseOutputTextTopLogprob {
1408 #[serde(default)]
1410 pub token: String,
1411 #[serde(default)]
1413 pub bytes: Vec<u8>,
1414 #[serde(default)]
1416 pub logprob: f64,
1417 #[serde(flatten)]
1419 pub extra: BTreeMap<String, Value>,
1420}
1421
1422#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
1424pub struct ResponseOutputTextLogprob {
1425 #[serde(default)]
1427 pub token: String,
1428 #[serde(default)]
1430 pub bytes: Vec<u8>,
1431 #[serde(default)]
1433 pub logprob: f64,
1434 #[serde(default)]
1436 pub top_logprobs: Vec<ResponseOutputTextTopLogprob>,
1437 #[serde(flatten)]
1439 pub extra: BTreeMap<String, Value>,
1440}
1441
1442#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1444pub struct ResponseOutputText {
1445 #[serde(default)]
1447 pub annotations: Vec<ResponseOutputTextAnnotation>,
1448 #[serde(default)]
1450 pub text: String,
1451 pub logprobs: Option<Vec<ResponseOutputTextLogprob>>,
1453 #[serde(flatten)]
1455 pub extra: BTreeMap<String, Value>,
1456}
1457
1458#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1460pub struct ResponseOutputRefusal {
1461 #[serde(default)]
1463 pub refusal: String,
1464 #[serde(flatten)]
1466 pub extra: BTreeMap<String, Value>,
1467}
1468
1469#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1471pub struct ResponseCreateParams {
1472 #[serde(skip_serializing_if = "Option::is_none")]
1474 pub model: Option<String>,
1475 #[serde(skip_serializing_if = "Option::is_none")]
1477 pub input: Option<ResponseInputPayload>,
1478 #[serde(skip_serializing_if = "Option::is_none")]
1480 pub temperature: Option<f32>,
1481 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1483 pub tools: Vec<ChatToolDefinition>,
1484 #[serde(skip_serializing_if = "Option::is_none")]
1486 pub stream: Option<bool>,
1487}
1488
1489fn default_function_type() -> String {
1490 "function".into()
1491}
1492
1493fn parse_jsonish_payload<T>(payload: &str) -> Result<T>
1494where
1495 T: serde::de::DeserializeOwned,
1496{
1497 let trimmed = payload.trim();
1498 let normalized = trimmed
1499 .strip_prefix("```json")
1500 .or_else(|| trimmed.strip_prefix("```"))
1501 .map(|value| value.trim())
1502 .and_then(|value| value.strip_suffix("```"))
1503 .map_or(trimmed, str::trim);
1504 serde_json::from_str(normalized).map_err(|error| {
1505 Error::Serialization(crate::SerializationError::new(format!(
1506 "结构化 JSON 解析失败: {error}"
1507 )))
1508 })
1509}
1510
1511fn parse_json_arguments<T>(arguments: &str) -> Result<T>
1512where
1513 T: serde::de::DeserializeOwned,
1514{
1515 serde_json::from_str(arguments).map_err(|error| {
1516 Error::Serialization(crate::SerializationError::new(format!(
1517 "工具参数 JSON 解析失败: {error}"
1518 )))
1519 })
1520}
1521
1522handle!(
1523 AdminResource
1525);
1526handle!(
1527 AdminOrganizationResource
1529);
1530handle!(
1531 AdminOrganizationAuditLogsResource
1533);
1534handle!(
1535 AdminOrganizationAdminApiKeysResource
1537);
1538handle!(
1539 AdminOrganizationUsageResource
1541);
1542handle!(
1543 AdminOrganizationInvitesResource
1545);
1546handle!(
1547 AdminOrganizationUsersResource
1549);
1550handle!(
1551 AdminOrganizationUserRolesResource
1553);
1554handle!(
1555 AdminOrganizationGroupsResource
1557);
1558handle!(
1559 AdminOrganizationGroupUsersResource
1561);
1562handle!(
1563 AdminOrganizationGroupRolesResource
1565);
1566handle!(
1567 AdminOrganizationRolesResource
1569);
1570handle!(
1571 AdminOrganizationDataRetentionResource
1573);
1574handle!(
1575 AdminOrganizationSpendAlertsResource
1577);
1578handle!(
1579 AdminOrganizationCertificatesResource
1581);
1582handle!(
1583 AdminOrganizationProjectsResource
1585);
1586handle!(
1587 AdminProjectUsersResource
1589);
1590handle!(
1591 AdminProjectUserRolesResource
1593);
1594handle!(
1595 AdminProjectServiceAccountsResource
1597);
1598handle!(
1599 AdminProjectApiKeysResource
1601);
1602handle!(
1603 AdminProjectRateLimitsResource
1605);
1606handle!(
1607 AdminProjectModelPermissionsResource
1609);
1610handle!(
1611 AdminProjectHostedToolPermissionsResource
1613);
1614handle!(
1615 AdminProjectGroupsResource
1617);
1618handle!(
1619 AdminProjectGroupRolesResource
1621);
1622handle!(
1623 AdminProjectRolesResource
1625);
1626handle!(
1627 AdminProjectDataRetentionResource
1629);
1630handle!(
1631 AdminProjectSpendAlertsResource
1633);
1634handle!(
1635 AdminProjectCertificatesResource
1637);
1638handle!(
1639 CompletionsResource
1641);
1642handle!(
1643 ChatResource
1645);
1646handle!(
1647 ChatCompletionsResource
1649);
1650handle!(
1651 ChatCompletionMessagesResource
1653);
1654handle!(
1655 EmbeddingsResource
1657);
1658handle!(
1659 FilesResource
1661);
1662handle!(
1663 ImagesResource
1665);
1666handle!(
1667 AudioResource
1669);
1670handle!(
1671 AudioSpeechResource
1673);
1674handle!(
1675 AudioTranscriptionsResource
1677);
1678handle!(
1679 AudioTranslationsResource
1681);
1682handle!(
1683 ModerationsResource
1685);
1686handle!(
1687 ModelsResource
1689);
1690handle!(
1691 FineTuningResource
1693);
1694handle!(
1695 FineTuningJobsResource
1697);
1698handle!(
1699 FineTuningJobCheckpointsResource
1701);
1702handle!(
1703 FineTuningCheckpointPermissionsResource
1705);
1706handle!(
1707 FineTuningAlphaResource
1709);
1710handle!(
1711 FineTuningAlphaGradersResource
1713);
1714handle!(
1715 GradersResource
1717);
1718handle!(
1719 VectorStoresResource
1721);
1722handle!(
1723 VectorStoreFilesResource
1725);
1726handle!(
1727 VectorStoreFileBatchesResource
1729);
1730handle!(
1731 BatchesResource
1733);
1734handle!(
1735 UploadsResource
1737);
1738handle!(
1739 UploadPartsResource
1741);
1742handle!(
1743 ResponsesResource
1745);
1746handle!(
1747 ResponseInputItemsResource
1749);
1750handle!(
1751 ResponseInputTokensResource
1753);
1754handle!(
1755 RealtimeResource
1757);
1758handle!(
1759 RealtimeClientSecretsResource
1761);
1762handle!(
1763 RealtimeCallsResource
1765);
1766handle!(
1767 ConversationsResource
1769);
1770handle!(
1771 ConversationItemsResource
1773);
1774handle!(
1775 EvalsResource
1777);
1778handle!(
1779 EvalRunsResource
1781);
1782handle!(
1783 EvalRunOutputItemsResource
1785);
1786handle!(
1787 ContainersResource
1789);
1790handle!(
1791 ContainerFilesResource
1793);
1794handle!(
1795 ContainerFilesContentResource
1797);
1798handle!(
1799 SkillsResource
1801);
1802handle!(
1803 SkillsContentResource
1805);
1806handle!(
1807 SkillVersionsResource
1809);
1810handle!(
1811 SkillVersionsContentResource
1813);
1814handle!(
1815 VideosResource
1817);
1818handle!(
1819 WebhooksResource
1821);
1822handle!(
1823 BetaResource
1825);
1826handle!(
1827 BetaAssistantsResource
1829);
1830handle!(
1831 BetaThreadsResource
1833);
1834handle!(
1835 BetaThreadMessagesResource
1837);
1838handle!(
1839 BetaThreadRunsResource
1841);
1842handle!(
1843 BetaThreadRunStepsResource
1845);
1846handle!(
1847 BetaChatkitResource
1849);
1850handle!(
1851 BetaChatkitSessionsResource
1853);
1854handle!(
1855 BetaChatkitThreadsResource
1857);
1858handle!(
1859 BetaRealtimeResource
1861);
1862handle!(
1863 BetaRealtimeSessionsResource
1865);
1866handle!(
1867 BetaRealtimeTranscriptionSessionsResource
1869);