forge_agent/runtime_integration.rs
1//! Runtime integration for Agent with ForgeRuntime.
2//!
3//! This module provides integration between the Agent and ForgeRuntime
4//! for coordinated file watching, caching, and automatic re-indexing.
5
6use crate::{Agent, AgentError, LoopResult};
7use forge_runtime::ForgeRuntime;
8use std::path::Path;
9
10impl Agent {
11 /// Creates agent with runtime for file watching and caching.
12 ///
13 /// This method initializes both the Agent and ForgeRuntime, allowing
14 /// the agent to leverage runtime services like query caching and
15 /// coordinated file watching.
16 ///
17 /// # Arguments
18 ///
19 /// * `codebase_path` - Path to the codebase
20 ///
21 /// # Returns
22 ///
23 /// Returns a tuple of (Agent, ForgeRuntime) on success.
24 ///
25 /// # Example
26 ///
27 /// ```no_run
28 /// use forge_agent::Agent;
29 ///
30 /// # #[tokio::main]
31 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
32 /// let (agent, mut runtime) = Agent::with_runtime("./project").await?;
33 ///
34 /// // Start file watching
35 /// runtime.watch().await?;
36 ///
37 /// // Run agent with runtime coordination
38 /// let result = agent.run_with_runtime(&mut runtime, "refactor function").await?;
39 /// # Ok(())
40 /// # }
41 /// ```
42 pub async fn with_runtime(
43 codebase_path: impl AsRef<Path>,
44 ) -> Result<(Self, ForgeRuntime), AgentError> {
45 let path = codebase_path.as_ref();
46
47 // Create runtime first
48 let runtime = ForgeRuntime::new(path)
49 .await
50 .map_err(|e| AgentError::ObservationFailed(format!("Failed to create runtime: {}", e)))?;
51
52 // Create agent with runtime's forge (shares the same graph store)
53 let agent = Agent::new(path).await?;
54
55 Ok((agent, runtime))
56 }
57
58 /// Runs agent loop with runtime coordination.
59 ///
60 /// This method coordinates with ForgeRuntime for optimal performance:
61 /// - Query cache access for faster graph operations
62 /// - Metrics collection for observability
63 ///
64 /// Note: For v0.4, watcher pause/resume is deferred to future versions.
65 /// The runtime provides cache access and metrics, but file watching
66 /// coordination is a future enhancement.
67 ///
68 /// # Arguments
69 ///
70 /// * `runtime` - Mutable reference to the ForgeRuntime
71 /// * `query` - The natural language query or request
72 ///
73 /// # Returns
74 ///
75 /// Returns `LoopResult` with transaction ID, modified files, and audit trail.
76 ///
77 /// # Example
78 ///
79 /// ```no_run
80 /// use forge_agent::Agent;
81 ///
82 /// # #[tokio::main]
83 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
84 /// let (agent, mut runtime) = Agent::with_runtime("./project").await?;
85 /// let result = agent.run_with_runtime(&mut runtime, "add error handling").await?;
86 /// # Ok(())
87 /// # }
88 /// ```
89 pub async fn run_with_runtime(
90 &self,
91 _runtime: &mut ForgeRuntime,
92 query: &str,
93 ) -> crate::Result<LoopResult> {
94 // For v0.4, we don't pause watcher (future enhancement)
95 // Just run the normal loop - runtime provides cache access and metrics
96
97 // TODO: Future version - Add watcher.pause() / watcher.resume()
98 // TODO: Future version - Utilize runtime cache for graph query optimization
99
100 self.run(query).await
101 }
102
103 /// Gets reference to runtime cache if available.
104 ///
105 /// This method provides access to the runtime's query cache for
106 /// optimization of repeated graph queries.
107 ///
108 /// # Returns
109 ///
110 /// Returns `None` - cache access requires runtime association (not yet implemented).
111 ///
112 /// Note: This is a placeholder for future functionality.
113 pub fn runtime_cache(&self) -> Option<()> {
114 // TODO: Return cache from associated runtime
115 // For v0.4, return None (cache access will be added in future version)
116 None
117 }
118
119 /// Gets runtime statistics if available.
120 ///
121 /// This method provides access to runtime metrics including cache size,
122 /// watch status, and reindex count.
123 ///
124 /// # Returns
125 ///
126 /// Returns `None` - stats access requires runtime association (not yet implemented).
127 ///
128 /// Note: This is a placeholder for future functionality.
129 pub fn runtime_stats(&self) -> Option<()> {
130 // TODO: Return stats from associated runtime
131 // For v0.4, return None
132 None
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[tokio::test]
141 async fn test_agent_with_runtime_creation() {
142 let temp = tempfile::tempdir().unwrap();
143 let (agent, runtime) = Agent::with_runtime(temp.path()).await.unwrap();
144
145 // Verify both agent and runtime were created
146 assert_eq!(agent.codebase_path, temp.path());
147 assert_eq!(runtime.codebase_path(), temp.path());
148 }
149
150 #[tokio::test]
151 async fn test_agent_run_with_runtime() {
152 let temp = tempfile::tempdir().unwrap();
153 let (agent, mut runtime) = Agent::with_runtime(temp.path()).await.unwrap();
154
155 // Run agent with runtime
156 let result = agent.run_with_runtime(&mut runtime, "test query").await;
157
158 // Should complete (may fail on actual query processing, but infrastructure works)
159 assert!(result.is_ok() || result.is_err());
160 }
161
162 #[tokio::test]
163 async fn test_agent_runtime_stats_returns_none() {
164 let temp = tempfile::tempdir().unwrap();
165 let (agent, _runtime) = Agent::with_runtime(temp.path()).await.unwrap();
166
167 // For v0.4, runtime_stats returns None
168 assert!(agent.runtime_stats().is_none());
169 }
170
171 #[tokio::test]
172 async fn test_agent_runtime_cache_returns_none() {
173 let temp = tempfile::tempdir().unwrap();
174 let (agent, _runtime) = Agent::with_runtime(temp.path()).await.unwrap();
175
176 // For v0.4, runtime_cache returns None
177 assert!(agent.runtime_cache().is_none());
178 }
179}