Skip to main content

livekit_api/services/
agent_dispatch.rs

1// Copyright 2025 LiveKit, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::{twirp_client::TwirpClient, ServiceBase, ServiceResult, LIVEKIT_PACKAGE};
16use crate::{
17    access_token::{AccessTokenError, VideoGrants},
18    get_env_keys,
19};
20use http::header::HeaderMap;
21use livekit_protocol as proto;
22
23const SVC: &str = "AgentDispatchService";
24
25#[derive(Debug)]
26pub struct AgentDispatchClient {
27    base: ServiceBase,
28    client: TwirpClient,
29}
30
31impl AgentDispatchClient {
32    pub fn with_api_key(host: &str, api_key: &str, api_secret: &str) -> Self {
33        Self {
34            base: ServiceBase::with_api_key(api_key, api_secret),
35            client: TwirpClient::new(host, LIVEKIT_PACKAGE, None),
36        }
37    }
38
39    pub fn new(host: &str) -> ServiceResult<Self> {
40        let (api_key, api_secret) = get_env_keys()?;
41        Ok(Self::with_api_key(host, &api_key, &api_secret))
42    }
43
44    /// Creates an explicit dispatch for an agent to join a room.
45    ///
46    /// To use explicit dispatch, your agent must be registered with an `agent_name`.
47    ///
48    /// # Arguments
49    /// * `req` - Request containing dispatch creation parameters. The request can include
50    ///   an optional `deployment` field to target a specific agent deployment.
51    ///   Leave empty to target the production deployment.
52    ///
53    /// # Returns
54    /// The created agent dispatch object
55    ///
56    pub async fn create_dispatch(
57        &self,
58        req: proto::CreateAgentDispatchRequest,
59    ) -> ServiceResult<proto::AgentDispatch> {
60        const METHOD: &str = "CreateDispatch";
61        let headers = self.auth_headers(req.room.to_string())?;
62        Ok(self.client.request(SVC, METHOD, req, headers).await?)
63    }
64
65    /// Deletes an explicit dispatch for an agent in a room.
66    ///
67    /// # Arguments
68    /// * `dispatch_id` - ID of the dispatch to delete
69    /// * `room_name` - Name of the room containing the dispatch
70    ///
71    /// # Returns
72    /// The deleted agent dispatch object
73    ///
74    pub async fn delete_dispatch(
75        &self,
76        dispatch_id: impl Into<String>,
77        room_name: impl Into<String>,
78    ) -> ServiceResult<proto::AgentDispatch> {
79        const METHOD: &str = "DeleteDispatch";
80        let req = proto::DeleteAgentDispatchRequest {
81            dispatch_id: dispatch_id.into(),
82            room: room_name.into(),
83        };
84        let headers = self.auth_headers(req.room.to_string())?;
85        Ok(self.client.request(SVC, METHOD, req, headers).await?)
86    }
87
88    /// Lists all agent dispatches in a room.
89    ///
90    /// # Arguments
91    /// * `room_name` - Name of the room to list dispatches from
92    ///
93    /// # Returns
94    /// List of dispatch objects in the room
95    ///
96    pub async fn list_dispatch(
97        &self,
98        room_name: impl Into<String>,
99    ) -> ServiceResult<Vec<proto::AgentDispatch>> {
100        const METHOD: &str = "ListDispatch";
101        let req = proto::ListAgentDispatchRequest { room: room_name.into(), ..Default::default() };
102        let headers = self.auth_headers(req.room.to_string())?;
103        let res: proto::ListAgentDispatchResponse =
104            self.client.request(SVC, METHOD, req, headers).await?;
105        Ok(res.agent_dispatches)
106    }
107
108    /// Gets an agent dispatch by ID.
109    ///
110    /// # Arguments
111    /// * `dispatch_id` - ID of the dispatch to retrieve
112    /// * `room_name` - Name of the room containing the dispatch
113    ///
114    /// # Returns
115    /// Requested dispatch object if found, `None` otherwise
116    ///
117    pub async fn get_dispatch(
118        &self,
119        dispatch_id: impl Into<String>,
120        room_name: impl Into<String>,
121    ) -> ServiceResult<Option<proto::AgentDispatch>> {
122        const METHOD: &str = "ListDispatch";
123        let req = proto::ListAgentDispatchRequest {
124            room: room_name.into(),
125            dispatch_id: dispatch_id.into(),
126        };
127        let headers = self.auth_headers(req.room.to_string())?;
128        let mut res: proto::ListAgentDispatchResponse =
129            self.client.request(SVC, METHOD, req, headers).await?;
130        Ok(res.agent_dispatches.pop())
131    }
132}
133
134impl AgentDispatchClient {
135    /// Generates the auth header common to all dispatch request types.
136    fn auth_headers(&self, room: String) -> Result<HeaderMap, AccessTokenError> {
137        self.base.auth_header(VideoGrants { room, room_admin: true, ..Default::default() }, None)
138    }
139}