ralph_workflow/phases/
context.rs1use crate::agents::{AgentRegistry, AgentRole};
8use crate::config::Config;
9use crate::guidelines::ReviewGuidelines;
10use crate::logger::{Colors, Logger};
11use crate::pipeline::Stats;
12use crate::pipeline::Timer;
13use crate::prompts::template_context::TemplateContext;
14
15pub struct PhaseContext<'a> {
20 pub config: &'a Config,
22 pub registry: &'a AgentRegistry,
24 pub logger: &'a Logger,
26 pub colors: &'a Colors,
28 pub timer: &'a mut Timer,
30 pub stats: &'a mut Stats,
32 pub developer_agent: &'a str,
34 pub reviewer_agent: &'a str,
36 pub review_guidelines: Option<&'a ReviewGuidelines>,
38 pub template_context: &'a TemplateContext,
40}
41
42impl PhaseContext<'_> {}
43
44pub fn get_primary_commit_agent(ctx: &PhaseContext<'_>) -> Option<String> {
50 let fallback_config = ctx.registry.fallback_config();
51
52 let commit_agents = fallback_config.get_fallbacks(AgentRole::Commit);
54 if !commit_agents.is_empty() {
55 return commit_agents.first().cloned();
57 }
58
59 let reviewer_agents = fallback_config.get_fallbacks(AgentRole::Reviewer);
61 if !reviewer_agents.is_empty() {
62 return reviewer_agents.first().cloned();
63 }
64
65 Some(ctx.reviewer_agent.to_string())
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use crate::config::Config;
73 use crate::logger::{Colors, Logger};
74 use crate::pipeline::{Stats, Timer};
75 use crate::prompts::template_context::TemplateContext;
76
77 struct TestFixture {
79 config: Config,
80 colors: Colors,
81 logger: Logger,
82 timer: Timer,
83 stats: Stats,
84 template_context: TemplateContext,
85 }
86
87 impl TestFixture {
88 fn new() -> Self {
89 let colors = Colors { enabled: false };
90 Self {
91 config: Config::default(),
92 colors,
93 logger: Logger::new(colors),
94 timer: Timer::new(),
95 stats: Stats::default(),
96 template_context: TemplateContext::default(),
97 }
98 }
99 }
100
101 #[test]
102 fn test_get_primary_commit_agent_uses_commit_chain_first() {
103 let mut registry = AgentRegistry::new().unwrap();
104
105 let toml_str = r#"
107 [agent_chain]
108 commit = ["commit-agent-1", "commit-agent-2"]
109 reviewer = ["reviewer-agent"]
110 developer = ["developer-agent"]
111 "#;
112 let unified: crate::config::UnifiedConfig = toml::from_str(toml_str).unwrap();
113 registry.apply_unified_config(&unified);
114
115 let mut fixture = TestFixture::new();
116 let ctx = PhaseContext {
117 config: &fixture.config,
118 registry: ®istry,
119 logger: &fixture.logger,
120 colors: &fixture.colors,
121 timer: &mut fixture.timer,
122 stats: &mut fixture.stats,
123 developer_agent: "developer-agent",
124 reviewer_agent: "reviewer-agent",
125 review_guidelines: None,
126 template_context: &fixture.template_context,
127 };
128
129 let result = get_primary_commit_agent(&ctx);
130 assert_eq!(
131 result,
132 Some("commit-agent-1".to_string()),
133 "Should use first agent from commit chain when configured"
134 );
135 }
136
137 #[test]
138 fn test_get_primary_commit_agent_falls_back_to_reviewer_chain() {
139 let mut registry = AgentRegistry::new().unwrap();
140
141 let toml_str = r#"
143 [agent_chain]
144 reviewer = ["reviewer-agent-1", "reviewer-agent-2"]
145 developer = ["developer-agent"]
146 "#;
147 let unified: crate::config::UnifiedConfig = toml::from_str(toml_str).unwrap();
148 registry.apply_unified_config(&unified);
149
150 let mut fixture = TestFixture::new();
151 let ctx = PhaseContext {
152 config: &fixture.config,
153 registry: ®istry,
154 logger: &fixture.logger,
155 colors: &fixture.colors,
156 timer: &mut fixture.timer,
157 stats: &mut fixture.stats,
158 developer_agent: "developer-agent",
159 reviewer_agent: "reviewer-agent-1",
160 review_guidelines: None,
161 template_context: &fixture.template_context,
162 };
163
164 let result = get_primary_commit_agent(&ctx);
165 assert_eq!(
166 result,
167 Some("reviewer-agent-1".to_string()),
168 "Should fall back to first agent from reviewer chain when commit chain is not configured"
169 );
170 }
171
172 #[test]
173 fn test_get_primary_commit_agent_uses_context_reviewer_as_last_resort() {
174 let registry = AgentRegistry::new().unwrap();
175 let mut fixture = TestFixture::new();
178 let ctx = PhaseContext {
179 config: &fixture.config,
180 registry: ®istry,
181 logger: &fixture.logger,
182 colors: &fixture.colors,
183 timer: &mut fixture.timer,
184 stats: &mut fixture.stats,
185 developer_agent: "fallback-developer",
186 reviewer_agent: "fallback-reviewer",
187 review_guidelines: None,
188 template_context: &fixture.template_context,
189 };
190
191 let result = get_primary_commit_agent(&ctx);
192
193 assert!(
197 result.is_some(),
198 "Should return Some agent even with no chains configured"
199 );
200
201 assert_ne!(
203 result.as_deref(),
204 Some("fallback-developer"),
205 "Should NOT fall back to developer agent - should use reviewer"
206 );
207 }
208}