1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::path::PathBuf;
9use std::time::Duration;
10
11use super::logger::LoggerConfig;
13
14pub use agent_client_protocol::{
16 ContentBlock, EnvVariable, Error, ImageContent, McpServer, Plan, SessionId, StopReason,
17 TextContent, ToolCall, ToolCallUpdate,
18};
19
20pub const PROTOCOL_VERSION: u32 = 1;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
25pub enum PermissionMode {
26 #[serde(rename = "auto")]
28 Auto,
29 #[serde(rename = "manual")]
31 Manual,
32 #[serde(rename = "selective")]
34 Selective,
35}
36
37impl Default for PermissionMode {
38 fn default() -> Self {
39 PermissionMode::Auto
40 }
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub enum ToolCallStatus {
46 #[serde(rename = "pending")]
48 Pending,
49 #[serde(rename = "in_progress")]
51 InProgress,
52 #[serde(rename = "completed")]
54 Completed,
55 #[serde(rename = "failed")]
57 Failed,
58 #[serde(rename = "running")]
60 Running,
61 #[serde(rename = "finished")]
63 Finished,
64 #[serde(rename = "error")]
66 Error,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
71pub enum PlanPriority {
72 #[serde(rename = "high")]
73 High,
74 #[serde(rename = "medium")]
75 Medium,
76 #[serde(rename = "low")]
77 Low,
78}
79
80impl Default for PlanPriority {
81 fn default() -> Self {
82 PlanPriority::Medium
83 }
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
88pub enum PlanStatus {
89 #[serde(rename = "pending")]
90 Pending,
91 #[serde(rename = "in_progress")]
92 InProgress,
93 #[serde(rename = "completed")]
94 Completed,
95}
96
97impl Default for PlanStatus {
98 fn default() -> Self {
99 PlanStatus::Pending
100 }
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize, Default)]
105pub struct PlanEntry {
106 pub content: String,
108 #[serde(default)]
110 pub priority: PlanPriority,
111 #[serde(default)]
113 pub status: PlanStatus,
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
120#[serde(untagged)]
121pub enum UserMessageChunk {
122 Text {
124 #[serde(rename = "text")]
125 content: String,
126 },
127 Path {
129 #[serde(rename = "path")]
130 path: PathBuf,
131 },
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct UserMessage {
139 #[serde(rename = "type")]
141 pub message_type: String,
142 pub chunks: Vec<UserMessageChunk>,
144}
145
146impl UserMessage {
147 pub fn new_text(text: String) -> Self {
155 Self {
156 message_type: "user".to_string(),
157 chunks: vec![UserMessageChunk::Text { content: text }],
158 }
159 }
160
161 pub fn new_path(path: PathBuf) -> Self {
169 Self {
170 message_type: "user".to_string(),
171 chunks: vec![UserMessageChunk::Path { path }],
172 }
173 }
174
175 pub fn new(chunks: Vec<UserMessageChunk>) -> Self {
183 Self {
184 message_type: "user".to_string(),
185 chunks,
186 }
187 }
188}
189
190#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct Icon {
193 #[serde(rename = "type")]
195 pub icon_type: String,
196 pub value: String,
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct ToolCallConfirmation {
203 #[serde(rename = "type")]
205 pub confirmation_type: String,
206 pub description: Option<String>,
208 pub command: Option<String>,
210 #[serde(rename = "rootCommand")]
212 pub root_command: Option<String>,
213 #[serde(rename = "serverName")]
215 pub server_name: Option<String>,
216 #[serde(rename = "toolName")]
218 pub tool_name: Option<String>,
219 #[serde(rename = "toolDisplayName")]
221 pub tool_display_name: Option<String>,
222 pub urls: Option<Vec<String>>,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct ToolCallContent {
229 #[serde(rename = "type")]
231 pub content_type: String,
232 pub markdown: Option<String>,
234 pub path: Option<String>,
236 #[serde(rename = "oldText")]
238 pub old_text: Option<String>,
239 #[serde(rename = "newText")]
241 pub new_text: Option<String>,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct ToolCallLocation {
247 pub path: String,
249 #[serde(rename = "lineStart")]
251 pub line_start: Option<u32>,
252 #[serde(rename = "lineEnd")]
254 pub line_end: Option<u32>,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct AgentInfo {
260 #[serde(rename = "agentId")]
262 pub agent_id: String,
263 #[serde(rename = "agentIndex")]
265 pub agent_index: Option<u32>,
266 #[serde(rename = "taskId")]
268 pub task_id: Option<String>,
269 pub timestamp: Option<u64>,
271}
272
273#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct ToolCallMessage {
276 #[serde(rename = "type")]
278 pub message_type: String,
279 pub id: String,
281 pub label: String,
283 pub icon: Icon,
285 pub status: ToolCallStatus,
287 #[serde(rename = "toolName")]
289 pub tool_name: Option<String>,
290 pub content: Option<ToolCallContent>,
292 pub locations: Option<Vec<ToolCallLocation>>,
294 pub confirmation: Option<ToolCallConfirmation>,
296 #[serde(rename = "agentId")]
298 pub agent_id: Option<String>,
299 #[serde(rename = "agentInfo")]
301 pub agent_info: Option<AgentInfo>,
302}
303
304impl ToolCallMessage {
305 pub fn new(id: String, label: String, icon: Icon, status: ToolCallStatus) -> Self {
316 Self {
317 message_type: "tool_call".to_string(),
318 id,
319 label,
320 icon,
321 status,
322 tool_name: None,
323 content: None,
324 locations: None,
325 confirmation: None,
326 agent_id: None,
327 agent_info: None,
328 }
329 }
330}
331
332#[derive(Debug, Clone)]
334pub struct WebSocketConfig {
335 pub url: Option<String>,
337 pub reconnect_attempts: u32,
339 pub reconnect_interval: Duration,
341}
342
343impl Default for WebSocketConfig {
344 fn default() -> Self {
345 Self {
346 url: Some("ws://localhost:8090/acp?peer=iflow".to_string()),
347 reconnect_attempts: 3,
348 reconnect_interval: Duration::from_secs(5),
349 }
350 }
351}
352
353impl WebSocketConfig {
354 pub fn new(url: String) -> Self {
356 Self {
357 url: Some(url),
358 ..Default::default()
359 }
360 }
361
362 pub fn auto_start() -> Self {
364 Self {
365 url: None,
366 ..Default::default()
367 }
368 }
369
370 pub fn with_reconnect_settings(
372 url: String,
373 reconnect_attempts: u32,
374 reconnect_interval: Duration,
375 ) -> Self {
376 Self {
377 url: Some(url),
378 reconnect_attempts,
379 reconnect_interval,
380 }
381 }
382
383 pub fn auto_start_with_reconnect_settings(
385 reconnect_attempts: u32,
386 reconnect_interval: Duration,
387 ) -> Self {
388 Self {
389 url: None,
390 reconnect_attempts,
391 reconnect_interval,
392 }
393 }
394}
395
396#[derive(Debug, Clone)]
398pub struct FileAccessConfig {
399 pub enabled: bool,
401 pub allowed_dirs: Option<Vec<PathBuf>>,
403 pub read_only: bool,
405 pub max_size: u64,
407}
408
409impl Default for FileAccessConfig {
410 fn default() -> Self {
411 Self {
412 enabled: false,
413 allowed_dirs: None,
414 read_only: false,
415 max_size: 10 * 1024 * 1024, }
417 }
418}
419
420#[derive(Debug, Clone)]
422pub struct ProcessConfig {
423 pub auto_start: bool,
425 pub start_port: Option<u16>,
427 pub debug: bool,
429}
430
431impl Default for ProcessConfig {
432 fn default() -> Self {
433 Self {
434 auto_start: true,
435 start_port: None, debug: false,
437 }
438 }
439}
440
441impl ProcessConfig {
442 pub fn new() -> Self {
444 Self::default()
445 }
446
447 pub fn auto_start(mut self, auto_start: bool) -> Self {
449 self.auto_start = auto_start;
450 self
451 }
452
453 pub fn start_port(mut self, port: u16) -> Self {
455 self.start_port = Some(port);
456 self
457 }
458
459 pub fn debug(mut self, debug: bool) -> Self {
461 self.debug = debug;
462 self
463 }
464
465 pub fn manual_start(self) -> Self {
467 self.auto_start(false)
468 }
469
470 pub fn enable_auto_start(self) -> Self {
472 self.auto_start(true)
473 }
474
475 pub fn enable_debug(self) -> Self {
477 self.debug(true)
478 }
479
480 pub fn stdio_mode(mut self) -> Self {
482 self.start_port = None;
483 self
484 }
485}
486
487#[derive(Debug, Clone)]
489pub struct LoggingConfig {
490 pub enabled: bool,
492 pub level: String,
494 pub logger_config: LoggerConfig,
496}
497
498impl Default for LoggingConfig {
499 fn default() -> Self {
500 Self {
501 enabled: false,
502 level: "INFO".to_string(),
503 logger_config: LoggerConfig::default(),
504 }
505 }
506}
507
508#[derive(Debug, Clone)]
513pub struct IFlowOptions {
514 pub cwd: PathBuf,
516 pub mcp_servers: Vec<McpServer>,
518 pub timeout: f64,
520 pub metadata: HashMap<String, serde_json::Value>,
522 pub file_access: FileAccessConfig,
524 pub process: ProcessConfig,
526 pub auth_method_id: Option<String>,
528 pub logging: LoggingConfig,
530 pub websocket: Option<WebSocketConfig>,
532 pub permission_mode: PermissionMode,
534}
535
536impl Default for IFlowOptions {
537 fn default() -> Self {
538 Self {
539 cwd: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
540 mcp_servers: Vec::new(),
541 timeout: 120.0,
542 metadata: HashMap::new(),
543 file_access: FileAccessConfig::default(),
544 process: ProcessConfig::default(),
545 auth_method_id: None,
546 logging: LoggingConfig::default(),
547 websocket: None,
548 permission_mode: PermissionMode::Auto,
549 }
550 }
551}
552
553impl IFlowOptions {
554 pub fn new() -> Self {
556 Self::default()
557 }
558
559 pub fn with_cwd(mut self, cwd: PathBuf) -> Self {
564 self.cwd = cwd;
565 self
566 }
567
568 pub fn with_timeout(mut self, timeout: f64) -> Self {
573 self.timeout = timeout;
574 self
575 }
576
577 pub fn with_mcp_servers(mut self, servers: Vec<McpServer>) -> Self {
582 self.mcp_servers = servers;
583 self
584 }
585
586 pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
591 self.metadata = metadata;
592 self
593 }
594
595 pub fn with_file_access_config(mut self, config: FileAccessConfig) -> Self {
600 self.file_access = config;
601 self
602 }
603
604 pub fn with_process_config(mut self, config: ProcessConfig) -> Self {
609 self.process = config;
610 self
611 }
612
613 pub fn with_auto_start(mut self, auto_start: bool) -> Self {
618 self.process.auto_start = auto_start;
619 self
620 }
621
622 pub fn with_auth_method_id(mut self, method_id: String) -> Self {
627 self.auth_method_id = Some(method_id);
628 self
629 }
630
631 pub fn with_logging_config(mut self, config: LoggingConfig) -> Self {
636 self.logging = config;
637 self
638 }
639
640 pub fn with_websocket_config(mut self, config: WebSocketConfig) -> Self {
645 self.websocket = Some(config);
646 self
647 }
648
649 pub fn with_permission_mode(mut self, mode: PermissionMode) -> Self {
654 self.permission_mode = mode;
655 self
656 }
657}
658
659#[derive(Debug, Clone, Serialize, Deserialize)]
661pub struct ErrorMessageDetails {
662 pub code: i32,
664 pub message: String,
666 #[serde(skip_serializing_if = "Option::is_none")]
668 pub details: Option<std::collections::HashMap<String, serde_json::Value>>,
669}
670
671impl ErrorMessageDetails {
672 pub fn new(code: i32, message: String) -> Self {
681 Self {
682 code,
683 message,
684 details: None,
685 }
686 }
687
688 pub fn with_details(
698 code: i32,
699 message: String,
700 details: std::collections::HashMap<String, serde_json::Value>,
701 ) -> Self {
702 Self {
703 code,
704 message,
705 details: Some(details),
706 }
707 }
708}
709
710#[derive(Debug, Clone, Serialize, Deserialize)]
715#[serde(tag = "type")]
716pub enum Message {
717 #[serde(rename = "user")]
719 User { content: String },
720
721 #[serde(rename = "assistant")]
723 Assistant { content: String },
724
725 #[serde(rename = "tool_call")]
727 ToolCall {
728 id: String,
729 name: String,
730 status: String,
731 },
732
733 #[serde(rename = "plan")]
735 Plan { entries: Vec<PlanEntry> },
736
737 #[serde(rename = "task_finish")]
739 TaskFinish { reason: Option<String> },
740
741 #[serde(rename = "error")]
743 Error {
744 code: i32,
745 message: String,
746 #[serde(skip_serializing_if = "Option::is_none")]
747 details: Option<std::collections::HashMap<String, serde_json::Value>>,
748 },
749}
750
751impl Message {
752 pub fn is_task_finish(&self) -> bool {
754 matches!(self, Message::TaskFinish { .. })
755 }
756
757 pub fn is_error(&self) -> bool {
759 matches!(self, Message::Error { .. })
760 }
761
762 pub fn get_text(&self) -> Option<&str> {
768 match self {
769 Message::User { content } => Some(content),
770 Message::Assistant { content } => Some(content),
771 _ => None,
772 }
773 }
774
775 pub fn error(code: i32, message: String) -> Self {
784 Message::Error {
785 code,
786 message,
787 details: None,
788 }
789 }
790
791 pub fn error_with_details(
801 code: i32,
802 message: String,
803 details: std::collections::HashMap<String, serde_json::Value>,
804 ) -> Self {
805 Message::Error {
806 code,
807 message,
808 details: Some(details),
809 }
810 }
811}