Skip to main content

zai_rs/agent/
mod.rs

1//! # Agent API Module
2//!
3//! Provides support for Zhipu AI's Agent API, enabling advanced AI agent
4//! interactions including creation, multi-turn conversations, tool use,
5//! and persistent state management.
6//!
7//! # Core Types
8//!
9//! - [`AgentClient`] — Main client for all agent operations
10//! - [`AgentCreateRequest`] — Request body for creating an agent
11//! - [`AgentChatRequest`] — Request body for sending a chat message
12//!
13//! # Usage
14//!
15//! ```rust,ignore
16//! use zai_rs::agent::{AgentClient, AgentCreateRequest};
17//!
18//! let client = AgentClient::new(api_key);
19//!
20//! // Create an agent
21//! let agent = client.create_agent(request).await?;
22//!
23//! // Chat with the agent
24//! let response = client.chat(&agent.id, chat_request).await?;
25//!
26//! // Retrieve conversation history
27//! let history = client.get_history(&agent.id, Some(10)).await?;
28//! ```
29
30use serde::{Deserialize, Serialize};
31
32use crate::client::{
33    endpoints::{ApiBase, EndpointConfig, build_query, join_url, paths},
34    http::{HttpClientConfig, parse_typed_response, send_empty_request, send_json_request},
35};
36
37pub mod request;
38pub mod response;
39
40pub use request::*;
41pub use response::*;
42
43/// Agent API path for creating and managing AI agents.
44pub const AGENT_API_PATH: &str = paths::AGENTS;
45
46/// Agent client for managing AI agent interactions
47///
48/// # Example
49///
50/// ```rust,ignore
51/// use zai_rs::agent::{AgentClient, AgentCreateRequest};
52///
53/// let client = AgentClient::new(api_key);
54/// let request = AgentCreateRequest::builder()
55///     .name("My Assistant")
56///     .description("A helpful assistant")
57///     .build();
58///
59/// let agent = client.create_agent(request).await?;
60/// ```
61pub struct AgentClient {
62    api_key: String,
63    endpoint_config: EndpointConfig,
64    api_base: ApiBase,
65    http_config: HttpClientConfig,
66}
67
68impl AgentClient {
69    /// Create a new Agent API client
70    pub fn new(api_key: impl Into<String>) -> Self {
71        let config = HttpClientConfig::default();
72        Self {
73            api_key: api_key.into(),
74            endpoint_config: EndpointConfig::default(),
75            api_base: ApiBase::PaasV4,
76            http_config: config,
77        }
78    }
79
80    /// Create a new agent with custom base URL
81    pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
82        self.api_base = ApiBase::Custom(base_url.into());
83        self
84    }
85
86    pub fn with_endpoint_config(mut self, endpoint_config: EndpointConfig) -> Self {
87        self.endpoint_config = endpoint_config;
88        self
89    }
90
91    /// Set custom HTTP client configuration (timeout, retries, etc.)
92    pub fn with_http_config(mut self, config: HttpClientConfig) -> Self {
93        self.http_config = config;
94        self
95    }
96
97    fn url(&self, path: &str) -> String {
98        self.endpoint_config.url(&self.api_base, path)
99    }
100
101    /// Create a new AI agent
102    pub async fn create_agent(
103        &self,
104        request: AgentCreateRequest,
105    ) -> crate::ZaiResult<AgentCreateResponse> {
106        self.send_request(&self.url(paths::AGENTS), &request).await
107    }
108
109    /// Get agent details by ID
110    pub async fn get_agent(&self, agent_id: &str) -> crate::ZaiResult<AgentDetails> {
111        let url = self.url(&join_url(paths::AGENTS, agent_id));
112        self.send_get_request(&url).await
113    }
114
115    /// Update an existing agent
116    pub async fn update_agent(
117        &self,
118        agent_id: &str,
119        request: AgentUpdateRequest,
120    ) -> crate::ZaiResult<AgentUpdateResponse> {
121        let url = self.url(&join_url(paths::AGENTS, agent_id));
122        self.send_request(&url, &request).await
123    }
124
125    /// Delete an agent
126    pub async fn delete_agent(&self, agent_id: &str) -> crate::ZaiResult<AgentDeleteResponse> {
127        let url = self.url(&join_url(paths::AGENTS, agent_id));
128        let response = send_empty_request(
129            reqwest::Method::DELETE,
130            url,
131            &self.api_key,
132            std::sync::Arc::new(self.http_config.clone()),
133        )
134        .await?;
135        parse_typed_response::<AgentDeleteResponse>(response).await
136    }
137
138    /// Send a chat message to an agent
139    pub async fn chat(
140        &self,
141        agent_id: &str,
142        request: AgentChatRequest,
143    ) -> crate::ZaiResult<AgentChatResponse> {
144        let url = self.url(&join_url(&join_url(paths::AGENTS, agent_id), "chat"));
145        self.send_request(&url, &request).await
146    }
147
148    /// Get conversation history
149    pub async fn get_history(
150        &self,
151        agent_id: &str,
152        limit: Option<u32>,
153    ) -> crate::ZaiResult<ConversationHistory> {
154        let base = self.url(&join_url(&join_url(paths::AGENTS, agent_id), "history"));
155        let url = match limit {
156            Some(l) => build_query(&base, [("limit", l.to_string())]),
157            None => base,
158        };
159        self.send_get_request(&url).await
160    }
161
162    /// Internal method to send POST requests (reuses connection pool)
163    async fn send_request<T: Serialize, R: for<'de> Deserialize<'de>>(
164        &self,
165        url: &str,
166        body: &T,
167    ) -> crate::ZaiResult<R> {
168        let response = send_json_request(
169            reqwest::Method::POST,
170            url.to_string(),
171            &self.api_key,
172            body,
173            std::sync::Arc::new(self.http_config.clone()),
174        )
175        .await?;
176        parse_typed_response::<R>(response).await
177    }
178
179    /// Internal method to send GET requests (reuses connection pool)
180    async fn send_get_request<R: for<'de> Deserialize<'de>>(
181        &self,
182        url: &str,
183    ) -> crate::ZaiResult<R> {
184        let response = send_empty_request(
185            reqwest::Method::GET,
186            url.to_string(),
187            &self.api_key,
188            std::sync::Arc::new(self.http_config.clone()),
189        )
190        .await?;
191        parse_typed_response::<R>(response).await
192    }
193}