Skip to main content

agent_base/types/
config.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
5pub enum Language {
6    #[default]
7    En,
8    Zh,
9}
10
11impl std::fmt::Display for Language {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        match self {
14            Language::En => write!(f, "en"),
15            Language::Zh => write!(f, "zh"),
16        }
17    }
18}
19
20#[derive(Clone, Debug)]
21pub struct RetryConfig {
22    pub max_retries: u32,
23    pub initial_backoff_ms: u64,
24    pub max_backoff_ms: u64,
25    pub backoff_multiplier: f64,
26    pub jitter: bool,
27}
28
29impl Default for RetryConfig {
30    fn default() -> Self {
31        Self {
32            max_retries: 3,
33            initial_backoff_ms: 500,
34            max_backoff_ms: 10_000,
35            backoff_multiplier: 2.0,
36            jitter: true,
37        }
38    }
39}
40
41impl RetryConfig {
42    pub fn new() -> Self {
43        Self::default()
44    }
45
46    pub fn max_retries(mut self, n: u32) -> Self {
47        self.max_retries = n;
48        self
49    }
50
51    pub fn initial_backoff_ms(mut self, ms: u64) -> Self {
52        self.initial_backoff_ms = ms;
53        self
54    }
55
56    pub fn max_backoff_ms(mut self, ms: u64) -> Self {
57        self.max_backoff_ms = ms;
58        self
59    }
60
61    pub fn no_jitter(mut self) -> Self {
62        self.jitter = false;
63        self
64    }
65}
66
67#[derive(Clone, Debug)]
68pub enum ResponseFormat {
69    JsonObject,
70    JsonSchema { name: String, schema: Value },
71}
72
73impl ResponseFormat {
74    pub fn to_api_value(&self) -> Value {
75        match self {
76            ResponseFormat::JsonObject => {
77                serde_json::json!({ "type": "json_object" })
78            }
79            ResponseFormat::JsonSchema { name, schema } => {
80                serde_json::json!({
81                    "type": "json_schema",
82                    "json_schema": {
83                        "name": name,
84                        "schema": schema,
85                    }
86                })
87            }
88        }
89    }
90}
91
92use crate::llm::ReasoningConfig;
93
94/// Safety configuration for agent runtime guardrails.
95///
96/// These limits are hard constraints enforced by code, not prompt —
97/// the model cannot bypass them regardless of its capability.
98#[derive(Clone, Debug)]
99pub struct SafetyConfig {
100    /// Maximum number of tool calls allowed per turn.
101    /// When exceeded, tool calls are discarded and the LLM is forced to summarize.
102    /// Default: 128.
103    pub max_tool_calls_per_turn: usize,
104
105    /// Maximum consecutive failures for the same tool before stopping retries.
106    /// Default: 3.
107    pub max_consecutive_failures: usize,
108}
109
110impl Default for SafetyConfig {
111    fn default() -> Self {
112        Self {
113            max_tool_calls_per_turn: 128,
114            max_consecutive_failures: 3,
115        }
116    }
117}
118
119#[derive(Clone, Debug, Default)]
120pub struct AgentConfig {
121    pub system_prompt: Option<String>,
122    /// Controls whether to include the reasoning content in LLM responses.
123    ///
124    /// Distinction from `reasoning.enabled`:
125    /// - `enable_thought`: controls whether the `reasoning_content` field is forwarded
126    ///   to consumers (i.e., "show the thinking process")
127    /// - `reasoning.enabled`: controls whether the model's extended thinking / reasoning
128    ///   mode is enabled (i.e., "let the model think deeply")
129    ///
130    /// Both are usually kept in sync, but can be controlled independently. For example,
131    /// to enable deep thinking without showing the process, set `enable_thought = false`
132    /// and `reasoning.enabled = true`.
133    pub enable_thought: bool,
134    /// Reasoning/thinking configuration that controls LLM reasoning behavior.
135    ///
136    /// - `enabled`: whether to enable extended thinking mode (equivalent to builder's `enable_thinking`)
137    /// - `budget_tokens`: thinking token budget cap
138    /// - `effort`: reasoning intensity/depth (semantics vary by provider)
139    pub reasoning: Option<ReasoningConfig>,
140    pub language: Language,
141    pub execution: ExecutionConfig,
142    pub llm: LlmConfig,
143    pub tool: ToolConfig,
144    pub session: SessionConfig,
145    pub safety: SafetyConfig,
146}
147
148impl AgentConfig {
149    /// Validate the configuration, returning an error for invalid values.
150    pub fn validate(&self) -> crate::types::AgentResult<()> {
151        use crate::types::AgentError;
152
153        if let Some(max_turns) = self.execution.max_turns
154            && max_turns == 0
155        {
156            return Err(AgentError::config_error(
157                "execution.max_turns must be > 0".to_string(),
158            ));
159        }
160
161        if let Some(max_sessions) = self.session.max_sessions
162            && max_sessions == 0
163        {
164            return Err(AgentError::config_error(
165                "session.max_sessions must be > 0".to_string(),
166            ));
167        }
168
169        if let Some(tool_timeout_ms) = self.tool.tool_timeout_ms
170            && tool_timeout_ms == 0
171        {
172            return Err(AgentError::config_error(
173                "tool.tool_timeout_ms must be > 0".to_string(),
174            ));
175        }
176
177        if self.safety.max_tool_calls_per_turn == 0 {
178            return Err(AgentError::config_error(
179                "safety.max_tool_calls_per_turn must be > 0".to_string(),
180            ));
181        }
182
183        Ok(())
184    }
185}
186
187#[derive(Clone, Debug, Default)]
188pub struct ExecutionConfig {
189    pub max_turns: Option<u32>,
190    pub approval_timeout_ms: Option<u64>,
191    pub fail_on_persist_error: bool,
192}
193
194#[derive(Clone, Debug, Default)]
195pub struct LlmConfig {
196    pub response_format: Option<ResponseFormat>,
197    pub llm_retry: Option<RetryConfig>,
198}
199
200#[derive(Clone, Debug, Default)]
201pub struct ToolConfig {
202    pub tool_timeout_ms: Option<u64>,
203    pub max_tool_output_chars: Option<usize>,
204    pub tool_error_retry_prompt: Option<String>,
205}
206
207#[derive(Clone, Debug, Default)]
208pub struct SessionConfig {
209    /// 最大 session 数量,超过时 LRU 逐出整个 session(从内存卸载,数据保留)
210    /// None = 不限制
211    pub max_sessions: Option<usize>,
212
213    /// 单个 session 最大保留轮数,超过从前面截掉最旧轮次
214    /// None = 不限制
215    pub max_turns_per_session: Option<usize>,
216
217    /// 单条消息 token 上限(安全阀),超过不存入 session 历史
218    /// 阈值应设很高(如 100k),只拦异常情况
219    /// None = 不限制
220    pub max_message_tokens: Option<usize>,
221}