ralph_workflow/agents/mod.rs
1//! Agent Abstraction Module
2//!
3//! Provides a pluggable agent system for different AI coding assistants
4//! (Claude, Codex, `OpenCode`, Goose, Cline, CCS, etc.)
5//!
6//! # Key Types
7//!
8//! - [`AgentRegistry`] - Registry for looking up and managing agent configurations
9//! - [`AgentConfig`] - Configuration for a single agent (command, flags, parser type)
10//! - [`AgentErrorKind`] - Error classification for fault-tolerant execution
11//! - [`JsonParserType`] - Parser selection for agent NDJSON output (Claude, Codex, Gemini, `OpenCode`, Generic)
12//!
13//! For detailed compatibility information, see
14//! [`docs/agent-compatibility.md`](https://codeberg.org/mistlight/RalphWithReviewer/src/branch/main/docs/agent-compatibility.md).
15//!
16//! ## Module Structure
17//!
18//! - `ccs` - CCS (Claude Code Switch) alias resolution
19//! - `config` - Agent configuration types and TOML parsing
20//! - `error` - Error classification for fault-tolerant execution
21//! - `fallback` - Fallback chain configuration for agent switching
22//! - `parser` - JSON parser type definitions
23//! - `providers` - `OpenCode` provider types and authentication
24//! - `registry` - Agent registry for agent lookup and management
25//!
26//! ## Configuration
27//!
28//! Agents can be configured via (in order of increasing priority):
29//! 1. Built-in defaults (claude, codex, opencode, ccs, aider, goose, cline, continue, amazon-q, gemini)
30//! 2. Unified config file (`~/.config/ralph-workflow.toml`)
31//! 3. Environment variables (`RALPH_DEVELOPER_CMD`, `RALPH_REVIEWER_CMD`)
32//! 4. Programmatic registration via `AgentRegistry::register()`
33//!
34//! ## CCS (Claude Code Switch) Support
35//!
36//! CCS aliases can be defined in the unified config and used with `ccs/alias` syntax:
37//! ```toml
38//! [ccs_aliases]
39//! work = "ccs work"
40//! personal = "ccs personal"
41//! gemini = "ccs gemini"
42//!
43//! [agent_chains]
44//! developer = ["ccs/work", "claude"]
45//!
46//! [agent_drains]
47//! planning = "developer"
48//! development = "developer"
49//! ```
50//!
51//! ## Agent Switching / Fallback
52//!
53//! Configure fallback agents for automatic switching when primary agent fails:
54//! ```toml
55//! [agent_chains]
56//! developer = ["claude", "codex", "goose"]
57//! reviewer = ["codex", "claude"]
58//!
59//! [agent_drains]
60//! planning = "developer"
61//! development = "developer"
62//! review = "reviewer"
63//! fix = "reviewer"
64//! commit = "reviewer"
65//! analysis = "developer"
66//!
67//! [agent_chain]
68//! max_retries = 3
69//! retry_delay_ms = 1000
70//! ```
71//!
72//! ## Example TOML Configuration
73//!
74//! ```toml
75//! [agents.myagent]
76//! cmd = "my-ai-tool run"
77//! output_flag = "--json-stream"
78//! yolo_flag = "--auto-fix"
79//! verbose_flag = "--verbose"
80//! can_commit = true
81//! json_parser = "claude" # Use Claude's JSON parser
82//! ```
83
84pub mod cache_environment;
85pub mod ccs;
86mod ccs_env;
87mod config;
88mod error;
89pub mod fallback;
90pub mod invoke;
91pub mod opencode_api;
92mod opencode_resolver;
93pub mod parser;
94mod providers;
95mod registry;
96mod retry_timer;
97pub mod runtime;
98pub mod validation;
99
100use std::sync::Arc;
101use std::time::Duration;
102
103// Re-export I/O implementations for backwards compatibility
104pub use cache_environment::{CacheEnvironment, RealCacheEnvironment};
105pub use ccs_env::{CcsEnvironment, CcsFilesystem};
106pub use ccs_env::{RealCcsEnvironment, RealCcsFilesystem};
107pub fn production_timer() -> Arc<dyn RetryTimerProviderDebug> {
108 Arc::new(ProductionRetryTimer)
109}
110
111pub trait RetryTimerProvider: Send + Sync {
112 fn sleep(&self, duration: Duration);
113}
114
115pub trait RetryTimerProviderDebug: RetryTimerProvider + std::fmt::Debug {}
116impl<T: RetryTimerProvider + std::fmt::Debug> RetryTimerProviderDebug for T {}
117
118#[derive(Debug, Clone)]
119pub struct ProductionRetryTimer;
120
121impl RetryTimerProvider for ProductionRetryTimer {
122 fn sleep(&self, duration: Duration) {
123 runtime::do_sleep(duration);
124 }
125}
126
127// Re-export public types for crate-level access
128pub use ccs::is_ccs_ref;
129pub use config::{
130 AgentConfig, AgentConfigBuilder, AgentsConfigFile, ConfigInitResult, ConfigSource,
131};
132pub use error::{contains_glm_model, is_glm_like_agent, AgentErrorKind};
133pub use fallback::{AgentDrain, AgentRole, DrainMode};
134pub use invoke::{AgentInput, AgentInvokeError, AgentInvoker, AgentOutput};
135pub use parser::JsonParserType;
136pub use providers::{
137 auth_failure_advice, strip_model_flag_prefix, validate_model_flag, OpenCodeProviderType,
138};
139pub use registry::AgentRegistry;
140
141#[cfg(test)]
142mod tests {
143 use super::fallback::FallbackConfig;
144 use super::*;
145
146 #[test]
147 fn test_module_exports() {
148 // Verify all expected types are accessible through the module
149 let _ = AgentRegistry::new().unwrap();
150 let _ = FallbackConfig::default();
151 let _ = AgentErrorKind::Permanent;
152 let _ = AgentRole::Developer;
153 let _ = JsonParserType::Claude;
154 let _ = OpenCodeProviderType::OpenCodeZen;
155 }
156}