Skip to main content

openai_interface/conversations/items/
mod.rs

1//! Manage the items of a conversation via
2//! `/conversations/{conversation_id}/items`.
3//!
4//! > ![warn] This module is untested!
5//! > If you encounter any issues, please report them on the repository.
6//!
7//! Items use the same shapes as Responses API input/output items, so
8//! the list response reuses
9//! [`ResponseOutputItem`].
10//! Submodules: [`create`], [`retrieve`] and [`delete`]; the list
11//! endpoint lives directly in this module.
12
13pub mod create;
14pub mod delete;
15pub mod retrieve;
16
17use url::Url;
18
19use crate::{
20    errors::OapiError,
21    pagination::PaginationQuery,
22    responses::ResponseOutputItem,
23    rest::get::{Get, GetNoStream},
24};
25
26/// Lists the items of a conversation.
27#[derive(Debug, Clone, Default)]
28pub struct ListConversationItemsRequest<'a> {
29    /// The ID of the conversation, e.g. `conv_...`.
30    pub conversation_id: &'a str,
31    /// The standard pagination parameters (`before`, `after`, `limit`,
32    /// `order`).
33    pub pagination: PaginationQuery<'a>,
34    /// Additional query parameters appended verbatim to the URL.
35    pub extra_query: Option<std::collections::HashMap<String, String>>,
36}
37
38impl Get for ListConversationItemsRequest<'_> {
39    /// Builds the URL for the request.
40    ///
41    /// `base_url` should be like <https://api.openai.com/v1>
42    fn build_url(&self, base_url: &str) -> Result<String, OapiError> {
43        let mut url = Url::parse(base_url.trim_end_matches('/')).map_err(OapiError::UrlError)?;
44        url.path_segments_mut()
45            .map_err(|_| OapiError::UrlCannotBeBase(base_url.to_string()))?
46            .push("conversations")
47            .push(self.conversation_id)
48            .push("items");
49
50        let mut touched = false;
51        {
52            let mut pairs = url.query_pairs_mut();
53            if self.pagination.any_set() {
54                self.pagination.append_to(&mut pairs);
55                touched = true;
56            }
57            if let Some(extra_query) = &self.extra_query {
58                for (key, value) in extra_query {
59                    pairs.append_pair(key, value);
60                }
61                touched = true;
62            }
63        }
64        if !touched {
65            url.set_query(None);
66        }
67
68        Ok(url.to_string())
69    }
70}
71
72impl GetNoStream for ListConversationItemsRequest<'_> {
73    type Response = ListConversationItemsResponse;
74}
75
76/// A single conversation item.
77///
78/// A thin wrapper over
79/// [`ResponseOutputItem`] so the
80/// retrieve endpoint can deserialize any item type (unknown types are
81/// preserved as `ResponseOutputItem::Other`).
82#[derive(Debug, Clone, serde::Deserialize)]
83pub struct ConversationItem(pub ResponseOutputItem);
84
85crate::impl_from_str!(ConversationItem);
86
87/// The response of listing a conversation's items.
88#[derive(Debug, Clone, serde::Deserialize)]
89pub struct ListConversationItemsResponse {
90    /// The items on this page. Item types unknown to this crate are
91    /// preserved as [`ResponseOutputItem::Other`].
92    #[serde(default)]
93    pub data: Vec<ResponseOutputItem>,
94    /// Whether more items exist after this page.
95    #[serde(default)]
96    pub has_more: Option<bool>,
97    /// The ID of the first item on the page, for cursor pagination.
98    #[serde(default)]
99    pub first_id: Option<String>,
100    /// The ID of the last item on the page, for cursor pagination.
101    #[serde(default)]
102    pub last_id: Option<String>,
103    /// The object type (`list`), if the provider sends it.
104    #[serde(default)]
105    pub object: Option<String>,
106}
107
108crate::impl_from_str!(ListConversationItemsResponse);