1use crate::domain::{
2 HookEvent, HookMatcher, PermissionMode, PermissionResult, Provider, ToolPermissionContext,
3};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::future::Future;
7use std::path::PathBuf;
8use std::pin::Pin;
9
10pub type SettingSource = String;
11
12#[derive(Clone, Default)]
13pub struct AgentOptions {
14 pub provider: Option<Provider>,
15 pub allowed_tools: Vec<String>,
16 pub disallowed_tools: Vec<String>,
17 pub system_prompt: Option<SystemPromptConfig>,
18 pub permission_mode: Option<PermissionMode>,
19 pub max_turns: Option<u32>,
20 pub model: Option<String>,
21 pub cwd: Option<PathBuf>,
22 pub create_cwd: bool,
23 pub cli_path: Option<PathBuf>,
24
25 pub mcp_servers: HashMap<String, McpServerConfig>,
27
28 pub continue_conversation: bool,
30 pub resume: Option<String>,
31 pub permission_prompt_tool_name: Option<String>,
32 pub add_dirs: Vec<PathBuf>,
33 pub env: HashMap<String, String>,
34 pub extra_args: HashMap<String, Option<String>>,
35 pub max_buffer_size: Option<usize>,
36
37 pub can_use_tool: Option<CanUseToolCallback>,
39 pub hooks: Option<HashMap<HookEvent, Vec<HookMatcher>>>,
40 pub stderr: Option<StderrCallback>,
41
42 pub include_partial_messages: bool,
44 pub fork_session: bool,
45 pub agents: HashMap<String, AgentDefinition>,
46 pub setting_sources: Option<Vec<SettingSource>>,
47}
48
49#[derive(Debug, Clone)]
50pub enum SystemPromptConfig {
51 Text(String),
52 Preset {
53 preset: String,
54 append: Option<String>,
55 },
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct AgentDefinition {
60 pub description: String,
61 pub prompt: String,
62 pub tools: Option<Vec<String>>,
63 pub model: Option<String>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67#[serde(tag = "type")]
68pub enum McpServerConfig {
69 #[serde(rename = "stdio")]
70 Stdio {
71 command: String,
72 #[serde(skip_serializing_if = "Option::is_none")]
73 args: Option<Vec<String>>,
74 #[serde(skip_serializing_if = "Option::is_none")]
75 env: Option<HashMap<String, String>>,
76 },
77
78 #[serde(rename = "sse")]
79 Sse {
80 url: String,
81 #[serde(skip_serializing_if = "Option::is_none")]
82 headers: Option<HashMap<String, String>>,
83 },
84
85 #[serde(rename = "http")]
86 Http {
87 url: String,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 headers: Option<HashMap<String, String>>,
90 },
91
92 #[serde(rename = "sdk")]
93 Sdk { name: String },
94}
95
96pub type CanUseToolCallback = std::sync::Arc<
97 dyn Fn(
98 String,
99 serde_json::Value,
100 ToolPermissionContext,
101 ) -> Pin<Box<dyn Future<Output = PermissionResult> + Send>>
102 + Send
103 + Sync,
104>;
105
106pub type StderrCallback = std::sync::Arc<dyn Fn(String) + Send + Sync>;
107
108impl std::fmt::Debug for AgentOptions {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 f.debug_struct("AgentOptions")
112 .field("provider", &self.provider)
113 .field("allowed_tools", &self.allowed_tools)
114 .field("disallowed_tools", &self.disallowed_tools)
115 .field("system_prompt", &self.system_prompt)
116 .field("permission_mode", &self.permission_mode)
117 .field("max_turns", &self.max_turns)
118 .field("model", &self.model)
119 .field("cwd", &self.cwd)
120 .field("create_cwd", &self.create_cwd)
121 .field("cli_path", &self.cli_path)
122 .field("mcp_servers", &self.mcp_servers)
123 .field("continue_conversation", &self.continue_conversation)
124 .field("resume", &self.resume)
125 .field(
126 "permission_prompt_tool_name",
127 &self.permission_prompt_tool_name,
128 )
129 .field("add_dirs", &self.add_dirs)
130 .field("env", &self.env)
131 .field("extra_args", &self.extra_args)
132 .field("max_buffer_size", &self.max_buffer_size)
133 .field(
134 "can_use_tool",
135 &self.can_use_tool.as_ref().map(|_| "<callback>"),
136 )
137 .field(
138 "hooks",
139 &self.hooks.as_ref().map(|h| format!("{} hooks", h.len())),
140 )
141 .field("stderr", &self.stderr.as_ref().map(|_| "<callback>"))
142 .field("include_partial_messages", &self.include_partial_messages)
143 .field("fork_session", &self.fork_session)
144 .field("agents", &self.agents)
145 .field("setting_sources", &self.setting_sources)
146 .finish()
147 }
148}