Skip to main content

cli_agents/
types.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4/// Supported CLI agents.
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7#[non_exhaustive]
8pub enum CliName {
9    Claude,
10    Codex,
11    Gemini,
12}
13
14impl std::fmt::Display for CliName {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        match self {
17            Self::Claude => write!(f, "claude"),
18            Self::Codex => write!(f, "codex"),
19            Self::Gemini => write!(f, "gemini"),
20        }
21    }
22}
23
24/// MCP server configuration.
25#[derive(Debug, Clone, Default, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase")]
27pub struct McpServer {
28    // ── stdio transport ──
29    pub command: Option<String>,
30    pub args: Option<Vec<String>>,
31    pub env: Option<HashMap<String, String>>,
32    pub cwd: Option<String>,
33
34    // ── HTTP/SSE transport ──
35    pub url: Option<String>,
36    #[serde(rename = "type")]
37    pub transport_type: Option<McpTransport>,
38    pub headers: Option<HashMap<String, String>>,
39
40    // ── Tool filtering ──
41    pub include_tools: Option<Vec<String>>,
42    pub exclude_tools: Option<Vec<String>>,
43
44    // ── Timeouts ──
45    pub timeout: Option<u64>,
46}
47
48#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
49#[serde(rename_all = "lowercase")]
50pub enum McpTransport {
51    Stdio,
52    Sse,
53    Http,
54}
55
56/// Filesystem setting sources Claude Code loads at startup.
57///
58/// Maps to the `--setting-sources` CLI flag. When omitted, the Claude CLI
59/// loads all three (user, project, local) and fires their hooks.
60/// Pass `Some(vec![])` to skip all of them — useful when embedding the CLI
61/// in another app that doesn't want global SessionStart hooks running.
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
63#[serde(rename_all = "lowercase")]
64pub enum SettingSource {
65    User,
66    Project,
67    Local,
68}
69
70impl SettingSource {
71    pub fn as_str(&self) -> &'static str {
72        match self {
73            Self::User => "user",
74            Self::Project => "project",
75            Self::Local => "local",
76        }
77    }
78}
79
80// ── Provider-specific options ──
81
82#[derive(Debug, Clone, Default, Serialize, Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct ClaudeOptions {
85    pub allowed_tools: Option<String>,
86    pub disallowed_tools: Option<String>,
87    pub tools: Option<String>,
88    pub append_system_prompt: Option<String>,
89    pub max_turns: Option<u32>,
90    pub max_budget_usd: Option<f64>,
91    pub max_thinking_tokens: Option<u32>,
92    pub continue_session: Option<bool>,
93    pub include_partial_messages: Option<bool>,
94    pub effort: Option<String>,
95    pub agents: Option<serde_json::Value>,
96    /// Filesystem settings the CLI loads (and fires hooks for).
97    /// `None` = let the CLI default (loads user/project/local).
98    /// `Some(vec![])` = load nothing — silences global SessionStart hooks.
99    pub setting_sources: Option<Vec<SettingSource>>,
100    /// Extra arguments appended verbatim to the Claude CLI invocation.
101    ///
102    /// Useful for flags this crate does not model explicitly — for example
103    /// `--json-schema <schema>` to force structured output, or
104    /// `--input-format text`. Order is preserved; entries are appended after
105    /// all flags this crate emits, so they can override earlier defaults.
106    pub extra_args: Option<Vec<String>>,
107}
108
109#[derive(Debug, Clone, Default, Serialize, Deserialize)]
110#[serde(rename_all = "camelCase")]
111pub struct CodexOptions {
112    pub approval_policy: Option<String>,
113    pub sandbox_mode: Option<String>,
114    pub additional_directories: Option<Vec<String>>,
115    pub images: Option<Vec<String>>,
116    pub output_schema: Option<String>,
117    /// Extra arguments appended verbatim to the Codex CLI invocation.
118    ///
119    /// Same semantics as the Claude / Gemini equivalents — pass any flags
120    /// this crate doesn't model. Appended last, so they can override earlier
121    /// defaults.
122    pub extra_args: Option<Vec<String>>,
123}
124
125#[derive(Debug, Clone, Default, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct GeminiOptions {
128    pub approval_mode: Option<String>,
129    pub sandbox: Option<bool>,
130    pub extra_args: Option<Vec<String>>,
131}
132
133#[derive(Debug, Clone, Default, Serialize, Deserialize)]
134pub struct ProviderOptions {
135    pub claude: Option<ClaudeOptions>,
136    pub codex: Option<CodexOptions>,
137    pub gemini: Option<GeminiOptions>,
138}
139
140/// Options passed to [`run()`](crate::run).
141#[derive(Debug, Clone, Default, Serialize, Deserialize)]
142#[serde(rename_all = "camelCase")]
143pub struct RunOptions {
144    /// Which CLI to use. If `None`, auto-discovers the first available.
145    pub cli: Option<CliName>,
146
147    /// The task/prompt to send to the agent.
148    pub task: String,
149
150    /// System prompt (where supported).
151    pub system_prompt: Option<String>,
152
153    /// Path to a system prompt file (alternative to inline `system_prompt`).
154    pub system_prompt_file: Option<String>,
155
156    /// MCP servers to connect.
157    pub mcp_servers: Option<HashMap<String, McpServer>>,
158
159    /// Working directory for the CLI process.
160    pub cwd: Option<String>,
161
162    /// Model name (e.g. "sonnet", "opus", "o3").
163    pub model: Option<String>,
164
165    /// Idle timeout in milliseconds. Default: 300_000 (5 minutes).
166    pub idle_timeout_ms: Option<u64>,
167
168    /// Total timeout in milliseconds. No default.
169    pub total_timeout_ms: Option<u64>,
170
171    /// Max consecutive tool failures before aborting. Default: 3.
172    pub max_consecutive_tool_failures: Option<u32>,
173
174    /// Extra environment variables for the CLI process.
175    pub env: Option<HashMap<String, String>>,
176
177    /// Explicit path to the CLI executable (skips discovery).
178    pub executable_path: Option<String>,
179
180    /// Session ID to resume a previous conversation.
181    pub resume_session_id: Option<String>,
182
183    /// Maximum bytes to buffer from CLI stdout before aborting.
184    ///
185    /// Prevents OOM if the CLI produces unexpectedly large output.
186    /// Defaults to 10 MB when `None`.
187    pub max_output_bytes: Option<usize>,
188
189    /// Skip permission prompts and run in fully autonomous mode.
190    ///
191    /// When `true`, passes provider-specific flags to bypass interactive approval
192    /// (e.g. `--dangerously-skip-permissions` for Claude). **Use with caution** —
193    /// the agent will be able to execute tools without human confirmation.
194    ///
195    /// Defaults to `false`.
196    #[serde(default)]
197    pub skip_permissions: bool,
198
199    /// Provider-specific options.
200    pub providers: Option<ProviderOptions>,
201}
202
203/// Result from a completed run.
204#[derive(Debug, Clone, Default, Serialize, Deserialize)]
205#[serde(rename_all = "camelCase")]
206#[non_exhaustive]
207pub struct RunResult {
208    pub success: bool,
209    pub text: Option<String>,
210    /// The process's exit status — `None` when a SIGNAL ended it, or when the
211    /// run never reached a process at all (cancellation).
212    ///
213    /// Do NOT read this as a diagnosis on its own: a CLI that reports failure
214    /// through its own event stream can exit 0, and in earlier versions a
215    /// signalled process was reported here as `1`. Prefer `success`, then
216    /// `text`, and consult `signal` before blaming the code.
217    pub exit_code: Option<i32>,
218    /// The signal that terminated the process, when one did. Unix only.
219    ///
220    /// `Some(9)` is the usual shape of an out-of-memory kill — the case that is
221    /// otherwise invisible, because a signalled process writes no stderr and
222    /// emits no final event.
223    pub signal: Option<i32>,
224    pub stats: Option<RunStats>,
225    pub session_id: Option<String>,
226    pub stderr: Option<String>,
227    pub cost_usd: Option<f64>,
228}
229
230#[derive(Debug, Clone, Default, Serialize, Deserialize)]
231#[serde(rename_all = "camelCase")]
232#[non_exhaustive]
233pub struct RunStats {
234    pub input_tokens: Option<u64>,
235    pub output_tokens: Option<u64>,
236    pub total_tokens: Option<u64>,
237    pub cached_tokens: Option<u64>,
238    pub duration_ms: Option<u64>,
239    pub tool_calls: Option<u32>,
240}