1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/// Configuration for model requests, tool execution, and hooks.
///
/// Construct validated options with [`AgentOptions::builder`]. `Default` leaves the
/// model and base URL empty without validation. Clones share tool handlers.
/// `max_tokens` and `temperature` remain unset unless explicitly supplied.
#[derive(Clone)]
pub struct AgentOptions {
/// System prompt that defines the agent's behavior and personality.
///
/// This is sent as the first message in the conversation to establish
/// context and instructions. Can be empty if no system-level guidance
/// is needed.
system_prompt: String,
/// Model identifier for the LLM to use (e.g., "qwen2.5-32b-instruct", "gpt-4").
///
/// This must match a model available at the configured `base_url`.
/// Different models have varying capabilities for tool use, context
/// length, and response quality.
model: String,
/// API endpoint URL (e.g., "http://localhost:1234/v1").
///
/// The wire format is chosen by `protocol`: `OpenAiChat` posts to
/// `{base_url}/chat/completions`, which local inference servers (LM Studio,
/// llama.cpp, vLLM) and most cloud providers support; `Anthropic` posts to
/// `{base_url}/messages`.
base_url: String,
/// API authentication key for the provider.
///
/// Many local servers don't require authentication, so the default
/// "not-needed" is often sufficient. For cloud providers like OpenAI,
/// set this to your actual API key.
api_key: String,
/// Caller-supplied HTTP headers applied to every model request.
///
/// These may override the protocol defaults, including authentication and content type.
/// Header names are matched case-insensitively when the builder replaces an earlier value.
headers: BTreeMap<String, String>,
/// Retained compatibility setting, stored but not enforced by the SDK.
///
/// Use `max_tool_iterations` to limit automatic tool rounds. Applications must
/// limit conversation turns themselves.
max_turns: u32,
/// Maximum tokens the model should generate in a single response.
///
/// `None` uses the provider's default. Lower values constrain response
/// length, which can be useful for cost control or ensuring concise answers.
/// Note this is separate from the model's context window size.
max_tokens: Option<u32>,
/// Optional sampling temperature. `None` omits the field and lets the server choose.
///
/// The builder accepts 0.0 through 2.0; a provider may accept a narrower range or
/// reject the parameter entirely.
temperature: Option<f32>,
/// HTTP request timeout in seconds.
///
/// Maximum time to wait for the API to respond. Applies per API call,
/// not to the entire conversation. Increase for slower models or when
/// expecting long responses.
timeout: u64,
/// Tools available for the agent to use during conversations.
///
/// Tools are wrapped in `Arc` for efficient cloning. When the agent
/// receives a tool use request, it looks up the tool by name in this
/// vector. Empty by default.
tools: Vec<Arc<Tool>>,
/// Whether the SDK executes tool calls and continues until a text response or
/// the configured iteration limit. Defaults to manual execution.
auto_execute_tools: bool,
/// Maximum automatic tool rounds. One round may contain several tool calls.
max_tool_iterations: u32,
/// Whether reasoning is emitted separately from content; defaults to false.
///
/// Reasoning never enters assistant text or conversation history.
include_reasoning: bool,
/// The wire protocol this endpoint speaks.
///
/// Selects the request path, the auth header, the body shape and the streaming
/// vocabulary. Defaults to [`ApiProtocol::OpenAiChat`], which is what every endpoint the
/// SDK supported before 0.9.0 speaks, so an existing configuration keeps its behaviour.
protocol: ApiProtocol,
/// Hooks for prompt submission and automatic pre/post-tool execution.
hooks: Hooks,
}
/// Omits credentials and shows tool counts instead of handlers.
impl std::fmt::Debug for AgentOptions {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AgentOptions")
.field("system_prompt", &self.system_prompt)
.field("model", &self.model)
.field("base_url", &self.base_url)
// Mask API key to prevent credential leakage in logs
.field("api_key", &"***")
.field("max_turns", &self.max_turns)
.field("max_tokens", &self.max_tokens)
.field("temperature", &self.temperature)
.field("timeout", &self.timeout)
// Show tool count instead of trying to debug Arc<Tool> contents
.field("tools", &format!("{} tools", self.tools.len()))
.field("auto_execute_tools", &self.auto_execute_tools)
.field("max_tool_iterations", &self.max_tool_iterations)
.field("include_reasoning", &self.include_reasoning)
.field("protocol", &self.protocol)
.field("hooks", &self.hooks)
.finish()
}
}
/// Defaults with an empty model and base URL. Use the builder for runtime validation.
impl Default for AgentOptions {
fn default() -> Self {
Self {
system_prompt: String::new(),
model: String::new(),
base_url: String::new(),
api_key: "not-needed".to_string(),
headers: BTreeMap::new(),
max_turns: 1,
max_tokens: None,
temperature: None,
timeout: 60,
tools: Vec::new(),
auto_execute_tools: false,
max_tool_iterations: 5,
hooks: Hooks::new(),
include_reasoning: false,
protocol: ApiProtocol::OpenAiChat,
}
}
}
impl AgentOptions {
/// Creates a builder that requires a model and base URL.
///
/// See [`AgentOptionsBuilder`] for an example.
pub fn builder() -> AgentOptionsBuilder {
AgentOptionsBuilder::default()
}
/// Returns the system prompt.
pub fn system_prompt(&self) -> &str {
&self.system_prompt
}
/// Returns the model identifier.
pub fn model(&self) -> &str {
&self.model
}
/// Returns the base URL.
pub fn base_url(&self) -> &str {
&self.base_url
}
/// Returns the API key.
pub fn api_key(&self) -> &str {
&self.api_key
}
/// Returns the caller-supplied HTTP headers.
pub fn headers(&self) -> &BTreeMap<String, String> {
&self.headers
}
/// Returns the retained `max_turns` compatibility value.
///
/// The SDK does not enforce it. Use [`max_tool_iterations`](Self::max_tool_iterations)
/// for automatic tool rounds and enforce conversation limits in your application.
pub fn max_turns(&self) -> u32 {
self.max_turns
}
/// Returns the maximum tokens setting.
pub fn max_tokens(&self) -> Option<u32> {
self.max_tokens
}
/// Returns the sampling temperature, or `None` when the server should choose.
pub fn temperature(&self) -> Option<f32> {
self.temperature
}
/// Returns the wire protocol this endpoint speaks.
pub fn protocol(&self) -> ApiProtocol {
self.protocol
}
/// Returns the HTTP timeout in seconds.
pub fn timeout(&self) -> u64 {
self.timeout
}
/// Returns a reference to the tools vector.
pub fn tools(&self) -> &[Arc<Tool>] {
&self.tools
}
/// Returns whether automatic tool execution is enabled.
pub fn auto_execute_tools(&self) -> bool {
self.auto_execute_tools
}
/// Returns the maximum tool execution iterations.
pub fn max_tool_iterations(&self) -> u32 {
self.max_tool_iterations
}
/// Returns a reference to the hooks configuration.
pub fn hooks(&self) -> &Hooks {
&self.hooks
}
/// Returns whether the reasoning channel is surfaced to the caller.
pub fn include_reasoning(&self) -> bool {
self.include_reasoning
}
}