livekit_api/services/
threads.rs1use std::time::Duration;
16
17use livekit_protocol::agent::{agent_task, agent_thread};
18use livekit_token::get_env_keys;
19
20use super::{ServiceBase, ServiceResult};
21use crate::public_api::{self as api, call, next_cursor, opt, page_size, types, PROJECT};
22
23#[derive(Debug)]
26pub struct ThreadClient {
27 client: api::Client,
28}
29
30impl ThreadClient {
31 pub fn with_api_key(host: &str, api_key: &str, api_secret: &str) -> Self {
33 Self::build(
34 host,
35 ServiceBase::with_api_key(api_key, api_secret),
36 crate::http_client::client(),
37 )
38 }
39
40 pub fn with_token(host: &str, token: &str) -> Self {
42 Self::build(host, ServiceBase::with_token(token), crate::http_client::client())
43 }
44
45 pub fn new(host: &str) -> ServiceResult<Self> {
48 let (api_key, api_secret) = get_env_keys()?;
49 Ok(Self::with_api_key(host, &api_key, &api_secret))
50 }
51
52 pub(crate) fn build(host: &str, base: ServiceBase, http: crate::http_client::Client) -> Self {
55 Self { client: api::client(host, base, http) }
56 }
57
58 pub fn with_request_timeout(mut self, timeout: Duration) -> Self {
60 self.client.inner.timeout = timeout;
61 self
62 }
63
64 pub async fn create(
65 &self,
66 req: agent_thread::CreateRequest,
67 ) -> ServiceResult<agent_thread::Thread> {
68 let body = types::ThreadServiceCreateThreadBody {
69 attributes: req.attributes,
70 idle_ttl: req.idle_ttl,
71 scope: opt(&req.scope).map(str::to_owned),
72 };
73 let res = call(self.client.thread_service_create_thread(PROJECT, &body)).await?;
74 Ok(res.thread.unwrap_or_default())
75 }
76
77 pub async fn get(&self, thread_id: &str) -> ServiceResult<agent_thread::Thread> {
78 let res = call(self.client.thread_service_get_thread(PROJECT, thread_id)).await?;
79 Ok(res.thread.unwrap_or_default())
80 }
81
82 pub async fn list(
84 &self,
85 req: agent_thread::ListRequest,
86 ) -> ServiceResult<agent_thread::ListResponse> {
87 let res = call(self.client.thread_service_list_threads(
88 PROJECT,
89 opt(&req.page_token),
90 page_size(req.limit),
91 opt(&req.scope),
92 ))
93 .await?;
94 Ok(agent_thread::ListResponse {
95 threads: res.items,
96 next_page_token: next_cursor(res.page_info),
97 })
98 }
99
100 pub async fn update(
101 &self,
102 req: agent_thread::UpdateRequest,
103 ) -> ServiceResult<agent_thread::Thread> {
104 let body = types::ThreadServiceUpdateThreadBody {
105 attributes: req.attributes,
106 idle_ttl: req.idle_ttl,
107 };
108 let res =
109 call(self.client.thread_service_update_thread(PROJECT, &req.thread_id, &body)).await?;
110 Ok(res.thread.unwrap_or_default())
111 }
112
113 pub async fn delete(&self, thread_id: &str) -> ServiceResult<()> {
115 call(self.client.thread_service_delete_thread(PROJECT, thread_id)).await?;
116 Ok(())
117 }
118
119 pub async fn items(
121 &self,
122 req: agent_thread::GetItemsRequest,
123 ) -> ServiceResult<agent_thread::GetItemsResponse> {
124 let sort_order = match agent_thread::SortOrder::try_from(req.sort_order) {
125 Ok(agent_thread::SortOrder::Asc) => {
126 Some(types::LivekitPublicapiCommonV1SortOrder::SortOrderAsc)
127 }
128 Ok(agent_thread::SortOrder::Desc) => {
129 Some(types::LivekitPublicapiCommonV1SortOrder::SortOrderDesc)
130 }
131 _ => None,
132 };
133 let res = call(self.client.thread_service_get_thread_items(
134 PROJECT,
135 &req.thread_id,
136 opt(&req.agent),
137 opt(&req.page_token),
138 page_size(req.limit),
139 sort_order,
140 ))
141 .await?;
142 Ok(agent_thread::GetItemsResponse {
143 items: res.items,
144 next_page_token: next_cursor(res.page_info),
145 })
146 }
147
148 pub async fn tasks(
150 &self,
151 req: agent_task::GetTasksRequest,
152 ) -> ServiceResult<agent_task::GetTasksResponse> {
153 let status = req.status.and_then(|s| agent_task::Status::try_from(s).ok());
154 let res = call(self.client.thread_service_get_thread_tasks(
155 PROJECT,
156 &req.thread_id,
157 opt(&req.page_token),
158 page_size(req.limit),
159 status.as_ref(),
160 ))
161 .await?;
162 Ok(agent_task::GetTasksResponse {
163 tasks: res.items,
164 next_page_token: next_cursor(res.page_info),
165 })
166 }
167}