1use crate::{
7 assistant::{
8 AssistantFileObject, AssistantFileRequest, AssistantObject, AssistantRequest,
9 DeletionStatus, ListAssistant, ListAssistantFile,
10 },
11 audio::{
12 AudioSpeechRequest, AudioSpeechResponse, AudioTranscriptionRequest,
13 AudioTranscriptionResponse, AudioTranslationRequest, AudioTranslationResponse,
14 },
15 chat_completion::{ChatCompletionRequest, ChatCompletionResponse},
16 completion::{CompletionRequest, CompletionResponse},
17 edit::{EditRequest, EditResponse},
18 embedding::{EmbeddingRequest, EmbeddingResponse},
19 error::APIError,
20 file::{
21 FileDeleteRequest, FileDeleteResponse, FileListResponse, FileRetrieveContentRequest,
22 FileRetrieveContentResponse, FileRetrieveRequest, FileRetrieveResponse, FileUploadRequest,
23 FileUploadResponse,
24 },
25 fine_tuning::{
26 CancelFineTuningJobRequest, CreateFineTuningJobRequest, FineTuningJobEvent,
27 FineTuningJobObject, FineTuningPagination, ListFineTuningJobEventsRequest,
28 RetrieveFineTuningJobRequest,
29 },
30 image::{
31 ImageEditRequest, ImageEditResponse, ImageGenerationRequest, ImageGenerationResponse,
32 ImageVariationRequest, ImageVariationResponse,
33 },
34 message::{
35 CreateMessageRequest, ListMessage, ListMessageFile, MessageFileObject, MessageObject,
36 ModifyMessageRequest,
37 },
38 moderation::{CreateModerationRequest, CreateModerationResponse},
39 run::{
40 CreateRunRequest, CreateThreadAndRunRequest, ListRun, ListRunStep, ModifyRunRequest,
41 RunObject, RunStepObject,
42 },
43 thread::{CreateThreadRequest, ModifyThreadRequest, ThreadObject},
44};
45use async_std::{
46 fs::{create_dir_all, File},
47 io::WriteExt,
48};
49use reqwest::{
50 header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_TYPE},
51 Client as ReqwestClient, Response,
52};
53use std::path::Path;
54
55const API_URL_V1: &str = "https://api.openai.com/v1";
56
57type ClientResult<T> = Result<T, APIError>;
59
60pub struct Client {
62 pub endpoint: String,
64 pub api_key: String,
66 pub client: ReqwestClient,
68}
69
70impl Client {
71 pub fn from_env() -> ClientResult<Self> {
73 let endpoint = std::env::var("OPENAI_API_BASE").unwrap_or_else(|_| API_URL_V1.to_owned());
74 let api_key = std::env::var("OPENAI_API_KEY").expect("OPENAI_API_KEY is not set");
75 let mut headers = HeaderMap::new();
76 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
77 headers.insert(
78 AUTHORIZATION,
79 HeaderValue::from_str(&format!("Bearer {}", api_key))?,
80 );
81
82 let client = ReqwestClient::builder().default_headers(headers).build()?;
83
84 Ok(Self {
85 endpoint,
86 api_key,
87 client,
88 })
89 }
90
91 pub fn new(api_key: String) -> ClientResult<Self> {
93 let mut headers = HeaderMap::new();
94 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
95 headers.insert(
96 AUTHORIZATION,
97 HeaderValue::from_str(&format!("Bearer {}", api_key))?,
98 );
99
100 let client = ReqwestClient::builder().default_headers(headers).build()?;
101
102 Ok(Self {
103 endpoint: API_URL_V1.to_owned(),
104 api_key,
105 client,
106 })
107 }
108
109 fn from_path(p: &str) -> String {
111 format!("{}{}", API_URL_V1, p)
112 }
113
114 pub async fn post<T: serde::ser::Serialize>(
116 &self,
117 path: &str,
118 params: &T,
119 ) -> ClientResult<Response> {
120 let url = Client::from_path(path);
121 self.client
122 .post(&url)
123 .json(params)
124 .send()
125 .await
126 .map_err(APIError::ReqwestError)
127 }
128
129 pub async fn get(&self, path: &str) -> ClientResult<Response> {
131 let url = Client::from_path(path);
132 self.client
133 .get(&url)
134 .send()
135 .await
136 .map_err(APIError::ReqwestError)
137 }
138
139 pub async fn delete(&self, path: &str) -> ClientResult<Response> {
141 let url = Client::from_path(path);
142 self.client
143 .delete(&url)
144 .send()
145 .await
146 .map_err(APIError::ReqwestError)
147 }
148
149 pub async fn completion(&self, req: CompletionRequest) -> ClientResult<CompletionResponse> {
151 let url = Client::from_path("/completions");
152 self.client
153 .post(&url)
154 .json(&req)
155 .send()
156 .await?
157 .json::<CompletionResponse>()
158 .await
159 .map_err(APIError::ReqwestError)
160 }
161
162 pub async fn edit(&self, req: EditRequest) -> ClientResult<EditResponse> {
164 let url = Client::from_path("/edits");
165 self.client
166 .post(&url)
167 .json(&req)
168 .send()
169 .await?
170 .json::<EditResponse>()
171 .await
172 .map_err(APIError::ReqwestError)
173 }
174
175 pub async fn image_generation(
177 &self,
178 req: ImageGenerationRequest,
179 ) -> ClientResult<ImageGenerationResponse> {
180 let url = Client::from_path("/images/generations");
181 self.client
182 .post(&url)
183 .json(&req)
184 .send()
185 .await?
186 .json::<ImageGenerationResponse>()
187 .await
188 .map_err(APIError::ReqwestError)
189 }
190
191 pub async fn image_edit(&self, req: ImageEditRequest) -> ClientResult<ImageEditResponse> {
193 let url = Client::from_path("/images/edits");
194 self.client
195 .post(&url)
196 .json(&req)
197 .send()
198 .await?
199 .json::<ImageEditResponse>()
200 .await
201 .map_err(APIError::ReqwestError)
202 }
203
204 pub async fn image_variation(
206 &self,
207 req: ImageVariationRequest,
208 ) -> ClientResult<ImageVariationResponse> {
209 let url = Client::from_path("/images/variations");
210 self.client
211 .post(&url)
212 .json(&req)
213 .send()
214 .await?
215 .json::<ImageVariationResponse>()
216 .await
217 .map_err(APIError::ReqwestError)
218 }
219
220 pub async fn embedding(&self, req: EmbeddingRequest) -> ClientResult<EmbeddingResponse> {
222 let url = Client::from_path("/embeddings");
223 self.client
224 .post(&url)
225 .json(&req)
226 .send()
227 .await?
228 .json::<EmbeddingResponse>()
229 .await
230 .map_err(APIError::ReqwestError)
231 }
232
233 pub async fn file_list(&self) -> ClientResult<FileListResponse> {
235 let url = Client::from_path("/files");
236 self.client
237 .get(&url)
238 .send()
239 .await?
240 .json::<FileListResponse>()
241 .await
242 .map_err(APIError::ReqwestError)
243 }
244
245 pub async fn file_upload(&self, req: FileUploadRequest) -> ClientResult<FileUploadResponse> {
247 let url = Client::from_path("/files");
248 self.client
249 .post(&url)
250 .json(&req)
251 .send()
252 .await?
253 .json::<FileUploadResponse>()
254 .await
255 .map_err(APIError::ReqwestError)
256 }
257
258 pub async fn file_delete(&self, req: FileDeleteRequest) -> ClientResult<FileDeleteResponse> {
260 let path = format!("/files/{}", req.file_id);
261 let url = Client::from_path(&path);
262 self.client
263 .delete(&url)
264 .send()
265 .await?
266 .json::<FileDeleteResponse>()
267 .await
268 .map_err(APIError::ReqwestError)
269 }
270
271 pub async fn file_retrieve(
273 &self,
274 req: FileRetrieveRequest,
275 ) -> ClientResult<FileRetrieveResponse> {
276 let path = format!("/files/{}", req.file_id);
277 let url = Client::from_path(&path);
278 self.client
279 .get(&url)
280 .send()
281 .await?
282 .json::<FileRetrieveResponse>()
283 .await
284 .map_err(APIError::ReqwestError)
285 }
286
287 pub async fn file_retrieve_content(
289 &self,
290 req: FileRetrieveContentRequest,
291 ) -> ClientResult<FileRetrieveContentResponse> {
292 let path = format!("/files/{}/content", req.file_id);
293 let url = Client::from_path(&path);
294 self.client
295 .get(&url)
296 .send()
297 .await?
298 .json::<FileRetrieveContentResponse>()
299 .await
300 .map_err(APIError::ReqwestError)
301 }
302
303 pub async fn chat_completion(
305 &self,
306 req: ChatCompletionRequest,
307 ) -> ClientResult<ChatCompletionResponse> {
308 let url = Client::from_path("/chat/completions");
309 self.client
310 .post(&url)
311 .json(&req)
312 .send()
313 .await?
314 .json::<ChatCompletionResponse>()
315 .await
316 .map_err(APIError::ReqwestError)
317 }
318
319 pub async fn audio_transcription(
321 &self,
322 req: AudioTranscriptionRequest,
323 ) -> ClientResult<AudioTranscriptionResponse> {
324 let url = Client::from_path("/audio/transcriptions");
325 self.client
326 .post(&url)
327 .json(&req)
328 .send()
329 .await?
330 .json::<AudioTranscriptionResponse>()
331 .await
332 .map_err(APIError::ReqwestError)
333 }
334
335 pub async fn audio_translation(
337 &self,
338 req: AudioTranslationRequest,
339 ) -> ClientResult<AudioTranslationResponse> {
340 let url = Client::from_path("/audio/translations");
341 self.client
342 .post(&url)
343 .json(&req)
344 .send()
345 .await?
346 .json::<AudioTranslationResponse>()
347 .await
348 .map_err(APIError::ReqwestError)
349 }
350
351 pub async fn audio_speech(&self, req: AudioSpeechRequest) -> ClientResult<AudioSpeechResponse> {
353 let url = Client::from_path("/audio/speech");
354 let response = self.client.post(&url).json(&req).send().await?;
355
356 let bytes = response.bytes().await?;
357 let path = Path::new(&req.output);
358 if let Some(parent) = path.parent() {
359 create_dir_all(parent).await?;
360 }
361
362 let mut file = File::create(path).await?;
363 file.write_all(&bytes).await?;
364
365 Ok(AudioSpeechResponse { result: true })
366 }
367
368 pub async fn create_fine_tuning_job(
370 &self,
371 req: CreateFineTuningJobRequest,
372 ) -> ClientResult<FineTuningJobObject> {
373 let url = Client::from_path("/fine_tuning/jobs");
374 self.client
375 .post(&url)
376 .json(&req)
377 .send()
378 .await?
379 .json::<FineTuningJobObject>()
380 .await
381 .map_err(APIError::ReqwestError)
382 }
383
384 pub async fn list_fine_tuning_jobs(
386 &self,
387 ) -> ClientResult<FineTuningPagination<FineTuningJobObject>> {
388 let url = Client::from_path("/fine_tuning/jobs");
389 self.client
390 .get(&url)
391 .send()
392 .await?
393 .json::<FineTuningPagination<FineTuningJobObject>>()
394 .await
395 .map_err(APIError::ReqwestError)
396 }
397
398 pub async fn list_fine_tuning_job_events(
400 &self,
401 req: ListFineTuningJobEventsRequest,
402 ) -> ClientResult<FineTuningPagination<FineTuningJobEvent>> {
403 let path = format!("/fine_tuning/jobs/{}/events", req.fine_tuning_job_id);
404 let url = Client::from_path(&path);
405 self.client
406 .get(&url)
407 .send()
408 .await?
409 .json::<FineTuningPagination<FineTuningJobEvent>>()
410 .await
411 .map_err(APIError::ReqwestError)
412 }
413
414 pub async fn retrieve_fine_tuning_job(
416 &self,
417 req: RetrieveFineTuningJobRequest,
418 ) -> ClientResult<FineTuningJobObject> {
419 let path = format!("/fine_tuning/jobs/{}", req.fine_tuning_job_id);
420 let url = Client::from_path(&path);
421 self.client
422 .get(&url)
423 .send()
424 .await?
425 .json::<FineTuningJobObject>()
426 .await
427 .map_err(APIError::ReqwestError)
428 }
429
430 pub async fn cancel_fine_tuning_job(
432 &self,
433 req: CancelFineTuningJobRequest,
434 ) -> ClientResult<FineTuningJobObject> {
435 let path = format!("/fine_tuning/jobs/{}/cancel", req.fine_tuning_job_id);
436 let url = Client::from_path(&path);
437 self.client
438 .post(&url)
439 .send()
440 .await?
441 .json::<FineTuningJobObject>()
442 .await
443 .map_err(APIError::ReqwestError)
444 }
445
446 pub async fn create_moderation(
448 &self,
449 req: CreateModerationRequest,
450 ) -> ClientResult<CreateModerationResponse> {
451 let url = Client::from_path("/content-moderation");
452 self.client
453 .post(&url)
454 .json(&req)
455 .send()
456 .await?
457 .json::<CreateModerationResponse>()
458 .await
459 .map_err(APIError::ReqwestError)
460 }
461
462 pub async fn create_assistant(&self, req: AssistantRequest) -> ClientResult<AssistantObject> {
464 let url = Client::from_path("/assistants");
465 self.client
466 .post(&url)
467 .json(&req)
468 .send()
469 .await?
470 .json::<AssistantObject>()
471 .await
472 .map_err(APIError::ReqwestError)
473 }
474
475 pub async fn retrieve_assistant(&self, assistant_id: String) -> ClientResult<AssistantObject> {
477 let path = format!("/assistants/{}", assistant_id);
478 let url = Client::from_path(&path);
479 self.client
480 .get(&url)
481 .send()
482 .await?
483 .json::<AssistantObject>()
484 .await
485 .map_err(APIError::ReqwestError)
486 }
487
488 pub async fn modify_assistant(
490 &self,
491 assistant_id: String,
492 req: AssistantRequest,
493 ) -> ClientResult<AssistantObject> {
494 let path = format!("/assistants/{}", assistant_id);
495 let url = Client::from_path(&path);
496 self.client
497 .post(&url)
498 .json(&req)
499 .send()
500 .await?
501 .json::<AssistantObject>()
502 .await
503 .map_err(APIError::ReqwestError)
504 }
505
506 pub async fn delete_assistant(&self, assistant_id: String) -> ClientResult<DeletionStatus> {
508 let path = format!("/assistants/{}", assistant_id);
509 let url = Client::from_path(&path);
510 self.client
511 .delete(&url)
512 .send()
513 .await?
514 .json::<DeletionStatus>()
515 .await
516 .map_err(APIError::ReqwestError)
517 }
518
519 pub async fn list_assistant(
521 &self,
522 limit: Option<i64>,
523 order: Option<String>,
524 after: Option<String>,
525 before: Option<String>,
526 ) -> ClientResult<ListAssistant> {
527 let base_url = Client::from_path("/assistants");
528 let url = Client::query_params(limit, order, after, before, base_url);
529 self.client
530 .get(&url)
531 .send()
532 .await?
533 .json::<ListAssistant>()
534 .await
535 .map_err(APIError::ReqwestError)
536 }
537
538 pub async fn create_assistant_file(
540 &self,
541 assistant_id: String,
542 req: AssistantFileRequest,
543 ) -> ClientResult<AssistantFileObject> {
544 let path = format!("/assistants/{}/files", assistant_id);
545 let url = Client::from_path(&path);
546 self.client
547 .post(&url)
548 .json(&req)
549 .send()
550 .await?
551 .json::<AssistantFileObject>()
552 .await
553 .map_err(APIError::ReqwestError)
554 }
555
556 pub async fn retrieve_assistant_file(
558 &self,
559 assistant_id: String,
560 file_id: String,
561 ) -> ClientResult<AssistantFileObject> {
562 let path = format!("/assistants/{}/files/{}", assistant_id, file_id);
563 let url = Client::from_path(&path);
564 self.client
565 .get(&url)
566 .send()
567 .await?
568 .json::<AssistantFileObject>()
569 .await
570 .map_err(APIError::ReqwestError)
571 }
572
573 pub async fn delete_assistant_file(
575 &self,
576 assistant_id: String,
577 file_id: String,
578 ) -> ClientResult<DeletionStatus> {
579 let path = format!("/assistants/{}/files/{}", assistant_id, file_id);
580 let url = Client::from_path(&path);
581 self.client
582 .delete(&url)
583 .send()
584 .await?
585 .json::<DeletionStatus>()
586 .await
587 .map_err(APIError::ReqwestError)
588 }
589
590 pub async fn list_assistant_file(
592 &self,
593 assistant_id: String,
594 limit: Option<i64>,
595 order: Option<String>,
596 after: Option<String>,
597 before: Option<String>,
598 ) -> ClientResult<ListAssistantFile> {
599 let path = format!("/assistants/{}/files", assistant_id);
600 let path = Client::query_params(limit, order, after, before, path);
601 let url = Client::from_path(&path);
602 self.client
603 .get(&url)
604 .send()
605 .await?
606 .json::<ListAssistantFile>()
607 .await
608 .map_err(APIError::ReqwestError)
609 }
610
611 pub async fn create_thread(&self, req: CreateThreadRequest) -> ClientResult<ThreadObject> {
613 let url = Client::from_path("/threads");
614 self.client
615 .post(&url)
616 .json(&req)
617 .send()
618 .await?
619 .json::<ThreadObject>()
620 .await
621 .map_err(APIError::ReqwestError)
622 }
623
624 pub async fn retrieve_thread(&self, thread_id: String) -> ClientResult<ThreadObject> {
626 let path = format!("/threads/{}", thread_id);
627 let url = Client::from_path(&path);
628 self.client
629 .get(&url)
630 .send()
631 .await?
632 .json::<ThreadObject>()
633 .await
634 .map_err(APIError::ReqwestError)
635 }
636
637 pub async fn modify_thread(
639 &self,
640 thread_id: String,
641 req: ModifyThreadRequest,
642 ) -> ClientResult<ThreadObject> {
643 let path = format!("/threads/{}", thread_id);
644 let url = Client::from_path(&path);
645 self.client
646 .post(&url)
647 .json(&req)
648 .send()
649 .await?
650 .json::<ThreadObject>()
651 .await
652 .map_err(APIError::ReqwestError)
653 }
654
655 pub async fn delete_thread(&self, thread_id: String) -> ClientResult<DeletionStatus> {
657 let path = format!("/threads/{}", thread_id);
658 let url = Client::from_path(&path);
659 self.client
660 .delete(&url)
661 .send()
662 .await?
663 .json::<DeletionStatus>()
664 .await
665 .map_err(APIError::ReqwestError)
666 }
667
668 pub async fn create_message(
670 &self,
671 thread_id: String,
672 req: CreateMessageRequest,
673 ) -> ClientResult<MessageObject> {
674 let path = format!("/threads/{}/messages", thread_id);
675 let url = Client::from_path(&path);
676 self.client
677 .post(&url)
678 .json(&req)
679 .send()
680 .await?
681 .json::<MessageObject>()
682 .await
683 .map_err(APIError::ReqwestError)
684 }
685
686 pub async fn retrieve_message(
688 &self,
689 thread_id: String,
690 message_id: String,
691 ) -> ClientResult<MessageObject> {
692 let path = format!("/threads/{}/messages/{}", thread_id, message_id);
693 let url = Client::from_path(&path);
694 self.client
695 .get(&url)
696 .send()
697 .await?
698 .json::<MessageObject>()
699 .await
700 .map_err(APIError::ReqwestError)
701 }
702
703 pub async fn modify_message(
705 &self,
706 thread_id: String,
707 message_id: String,
708 req: ModifyMessageRequest,
709 ) -> ClientResult<MessageObject> {
710 let path = format!("/threads/{}/messages/{}", thread_id, message_id);
711 let url = Client::from_path(&path);
712 self.client
713 .post(&url)
714 .json(&req)
715 .send()
716 .await?
717 .json::<MessageObject>()
718 .await
719 .map_err(APIError::ReqwestError)
720 }
721
722 pub async fn list_messages(&self, thread_id: String) -> ClientResult<ListMessage> {
724 let path = format!("/threads/{}/messages", thread_id);
725 let url = Client::from_path(&path);
726 self.client
727 .get(&url)
728 .send()
729 .await?
730 .json::<ListMessage>()
731 .await
732 .map_err(APIError::ReqwestError)
733 }
734
735 pub async fn retrieve_message_file(
737 &self,
738 thread_id: String,
739 message_id: String,
740 file_id: String,
741 ) -> ClientResult<MessageFileObject> {
742 let path = format!(
743 "/threads/{}/messages/{}/files/{}",
744 thread_id, message_id, file_id
745 );
746 let url = Client::from_path(&path);
747 self.client
748 .get(&url)
749 .send()
750 .await?
751 .json::<MessageFileObject>()
752 .await
753 .map_err(APIError::ReqwestError)
754 }
755
756 pub async fn list_message_file(
758 &self,
759 thread_id: String,
760 message_id: String,
761 limit: Option<i64>,
762 order: Option<String>,
763 after: Option<String>,
764 before: Option<String>,
765 ) -> ClientResult<ListMessageFile> {
766 let path = format!("/threads/{}/messages/{}/files", thread_id, message_id);
767 let path = Client::query_params(limit, order, after, before, path);
768 let url = Client::from_path(&path);
769 self.client
770 .get(&url)
771 .send()
772 .await?
773 .json::<ListMessageFile>()
774 .await
775 .map_err(APIError::ReqwestError)
776 }
777
778 pub async fn create_run(
780 &self,
781 thread_id: String,
782 req: CreateRunRequest,
783 ) -> ClientResult<RunObject> {
784 let path = format!("/threads/{}/runs", thread_id);
785 let url = Client::from_path(&path);
786 self.client
787 .post(&url)
788 .json(&req)
789 .send()
790 .await?
791 .json::<RunObject>()
792 .await
793 .map_err(APIError::ReqwestError)
794 }
795
796 pub async fn retrieve_run(&self, thread_id: String, run_id: String) -> ClientResult<RunObject> {
798 let path = format!("/threads/{}/runs/{}", thread_id, run_id);
799 let url = Client::from_path(&path);
800 self.client
801 .get(&url)
802 .send()
803 .await?
804 .json::<RunObject>()
805 .await
806 .map_err(APIError::ReqwestError)
807 }
808
809 pub async fn modify_run(
811 &self,
812 thread_id: String,
813 run_id: String,
814 req: ModifyRunRequest,
815 ) -> ClientResult<RunObject> {
816 let path = format!("/threads/{}/runs/{}", thread_id, run_id);
817 let url = Client::from_path(&path);
818 self.client
819 .post(&url)
820 .json(&req)
821 .send()
822 .await?
823 .json::<RunObject>()
824 .await
825 .map_err(APIError::ReqwestError)
826 }
827
828 pub async fn list_run(
830 &self,
831 thread_id: String,
832 limit: Option<i64>,
833 order: Option<String>,
834 after: Option<String>,
835 before: Option<String>,
836 ) -> ClientResult<ListRun> {
837 let path = format!("/threads/{}/runs", thread_id);
838 let path = Client::query_params(limit, order, after, before, path);
839 let url = Client::from_path(&path);
840 self.client
841 .get(&url)
842 .send()
843 .await?
844 .json::<ListRun>()
845 .await
846 .map_err(APIError::ReqwestError)
847 }
848
849 pub async fn cancel_run(&self, thread_id: String, run_id: String) -> ClientResult<RunObject> {
851 let path = format!("/threads/{}/runs/{}/cancel", thread_id, run_id);
852 let url = Client::from_path(&path);
853 let empty_req = ModifyRunRequest::new();
854 self.client
855 .post(&url)
856 .json(&empty_req)
857 .send()
858 .await?
859 .json::<RunObject>()
860 .await
861 .map_err(APIError::ReqwestError)
862 }
863
864 pub async fn create_thread_and_run(
866 &self,
867 req: CreateThreadAndRunRequest,
868 ) -> ClientResult<RunObject> {
869 let url = Client::from_path("/threads/runs");
870 self.client
871 .post(&url)
872 .json(&req)
873 .send()
874 .await?
875 .json::<RunObject>()
876 .await
877 .map_err(APIError::ReqwestError)
878 }
879
880 pub async fn retrieve_run_step(
882 &self,
883 thread_id: String,
884 run_id: String,
885 step_id: String,
886 ) -> ClientResult<RunStepObject> {
887 let path = format!("/threads/{}/runs/{}/steps/{}", thread_id, run_id, step_id);
888 let url = Client::from_path(&path);
889 self.client
890 .get(&url)
891 .send()
892 .await?
893 .json::<RunStepObject>()
894 .await
895 .map_err(APIError::ReqwestError)
896 }
897
898 pub async fn list_run_step(
900 &self,
901 thread_id: String,
902 run_id: String,
903 limit: Option<i64>,
904 order: Option<String>,
905 after: Option<String>,
906 before: Option<String>,
907 ) -> ClientResult<ListRunStep> {
908 let path = format!("/threads/{}/runs/{}/steps", thread_id, run_id);
909 let path = Client::query_params(limit, order, after, before, path);
910 let url = Client::from_path(&path);
911 self.client
912 .get(&url)
913 .send()
914 .await?
915 .json::<ListRunStep>()
916 .await
917 .map_err(APIError::ReqwestError)
918 }
919
920 fn query_params(
922 limit: Option<i64>,
923 order: Option<String>,
924 after: Option<String>,
925 before: Option<String>,
926 mut url: String,
927 ) -> String {
928 let mut params = String::new();
929 if let Some(limit) = limit {
930 params.push_str(&format!("limit={}&", limit));
931 }
932 if let Some(order) = order {
933 params.push_str(&format!("order={}&", order));
934 }
935 if let Some(after) = after {
936 params.push_str(&format!("after={}&", after));
937 }
938 if let Some(before) = before {
939 params.push_str(&format!("before={}&", before));
940 }
941 if !params.is_empty() {
942 url.push_str(&format!("?{params}"));
943 }
944 url
945 }
946}