Merge pull request #5 from dhanji/micn/agent-tweaks

load AGENTS.md if there
This commit is contained in:
Dhanji R. Prasanna
2025-10-16 15:06:14 +11:00
committed by GitHub
3 changed files with 105 additions and 33 deletions

View File

@@ -275,8 +275,11 @@ pub async fn run() -> Result<()> {
std::env::current_dir()? std::env::current_dir()?
}; };
// Check if we're in a project directory and read README if available // Check if we're in a project directory and read README and AGENTS.md if available
// This should happen in both interactive and autonomous modes // Load AGENTS.md first (if present) to provide agent-specific instructions
let agents_content = read_agents_config(&workspace_dir);
// Then load README for project context
let readme_content = read_project_readme(&workspace_dir); let readme_content = read_project_readme(&workspace_dir);
// Create project model // Create project model
@@ -320,10 +323,21 @@ pub async fn run() -> Result<()> {
// Initialize agent // Initialize agent
let ui_writer = ConsoleUiWriter::new(); let ui_writer = ConsoleUiWriter::new();
// Combine AGENTS.md and README content if both exist
let combined_content = match (agents_content.clone(), readme_content.clone()) {
(Some(agents), Some(readme)) => {
Some(format!("{}\n\n{}", agents, readme))
}
(Some(agents), None) => Some(agents),
(None, Some(readme)) => Some(readme),
(None, None) => None,
};
let mut agent = if cli.autonomous { let mut agent = if cli.autonomous {
Agent::new_autonomous_with_readme_and_quiet(config.clone(), ui_writer, readme_content.clone(), cli.quiet).await? Agent::new_autonomous_with_readme_and_quiet(config.clone(), ui_writer, combined_content.clone(), cli.quiet).await?
} else { } else {
Agent::new_with_readme_and_quiet(config.clone(), ui_writer, readme_content.clone(), cli.quiet).await? Agent::new_with_readme_and_quiet(config.clone(), ui_writer, combined_content.clone(), cli.quiet).await?
}; };
// Execute task, autonomous mode, or start interactive mode // Execute task, autonomous mode, or start interactive mode
@@ -364,20 +378,61 @@ pub async fn run() -> Result<()> {
cli.show_prompt, cli.show_prompt,
cli.show_code, cli.show_code,
cli.theme, cli.theme,
readme_content, combined_content,
) )
.await?; .await?;
} else { } else {
// Use standard terminal UI // Use standard terminal UI
let output = SimpleOutput::new(); let output = SimpleOutput::new();
output.print(&format!("📁 Workspace: {}", project.workspace().display())); output.print(&format!("📁 Workspace: {}", project.workspace().display()));
run_interactive(agent, cli.show_prompt, cli.show_code, readme_content).await?; run_interactive(agent, cli.show_prompt, cli.show_code, combined_content).await?;
} }
} }
Ok(()) Ok(())
} }
/// Check if we're in a project directory and read AGENTS.md if available
fn read_agents_config(workspace_dir: &Path) -> Option<String> {
// Look for AGENTS.md in the current directory
let agents_path = workspace_dir.join("AGENTS.md");
if agents_path.exists() {
match std::fs::read_to_string(&agents_path) {
Ok(content) => {
// Return the content with a note about which file was read
info!("Loaded AGENTS.md from {}", agents_path.display());
Some(format!(
"🤖 Agent Configuration (from AGENTS.md):\n\n{}",
content
))
}
Err(e) => {
// Log the error but continue without the agents config
error!("Failed to read AGENTS.md: {}", e);
None
}
}
} else {
// Check for alternative names
let alt_path = workspace_dir.join("agents.md");
if alt_path.exists() {
match std::fs::read_to_string(&alt_path) {
Ok(content) => {
info!("Loaded agents.md from {}", alt_path.display());
Some(format!("🤖 Agent Configuration (from agents.md):\n\n{}", content))
}
Err(e) => {
error!("Failed to read agents.md: {}", e);
None
}
}
} else {
None
}
}
}
/// Check if we're in a project directory and read README if available /// Check if we're in a project directory and read README if available
fn read_project_readme(workspace_dir: &Path) -> Option<String> { fn read_project_readme(workspace_dir: &Path) -> Option<String> {
// Check if we're in a project directory (contains .g3 or .git) // Check if we're in a project directory (contains .g3 or .git)
@@ -478,7 +533,7 @@ async fn run_interactive_retro(
show_prompt: bool, show_prompt: bool,
show_code: bool, show_code: bool,
theme_name: Option<String>, theme_name: Option<String>,
readme_content: Option<String>, combined_content: Option<String>,
) -> Result<()> { ) -> Result<()> {
use crossterm::event::{self, Event, KeyCode, KeyModifiers}; use crossterm::event::{self, Event, KeyCode, KeyModifiers};
use std::time::Duration; use std::time::Duration;
@@ -500,24 +555,31 @@ async fn run_interactive_retro(
// Create agent with RetroTuiWriter // Create agent with RetroTuiWriter
let ui_writer = RetroTuiWriter::new(tui.clone()); let ui_writer = RetroTuiWriter::new(tui.clone());
let mut agent = Agent::new_with_readme_and_quiet(config, ui_writer, readme_content.clone(), false).await?; let mut agent = Agent::new_with_readme_and_quiet(config, ui_writer, combined_content.clone(), false).await?;
// Display initial system messages // Display initial system messages
tui.output("SYSTEM: AGENT ONLINE\n\n"); tui.output("SYSTEM: AGENT ONLINE\n\n");
// Display message if README was loaded // Display message if AGENTS.md or README was loaded
if readme_content.is_some() { if let Some(ref content) = combined_content {
// Extract the first heading or title from the README // Check what was loaded
let readme_snippet = if let Some(ref content) = readme_content { let has_agents = content.contains("Agent Configuration");
extract_readme_heading(content) let has_readme = content.contains("Project README");
.unwrap_or_else(|| "PROJECT DOCUMENTATION LOADED".to_string())
} else { if has_agents {
"PROJECT DOCUMENTATION LOADED".to_string() tui.output("SYSTEM: AGENT CONFIGURATION LOADED\n\n");
}; }
tui.output(&format!(
"SYSTEM: PROJECT README LOADED - {}\n\n", if has_readme {
readme_snippet // Extract the first heading or title from the README
)); let readme_snippet = extract_readme_heading(content)
.unwrap_or_else(|| "PROJECT DOCUMENTATION LOADED".to_string());
tui.output(&format!(
"SYSTEM: PROJECT README LOADED - {}\n\n",
readme_snippet
));
}
} }
tui.output("SYSTEM: READY FOR INPUT\n\n"); tui.output("SYSTEM: READY FOR INPUT\n\n");
tui.output("\n\n"); tui.output("\n\n");
@@ -739,7 +801,7 @@ async fn run_interactive<W: UiWriter>(
mut agent: Agent<W>, mut agent: Agent<W>,
show_prompt: bool, show_prompt: bool,
show_code: bool, show_code: bool,
readme_content: Option<String>, combined_content: Option<String>,
) -> Result<()> { ) -> Result<()> {
let output = SimpleOutput::new(); let output = SimpleOutput::new();
@@ -758,17 +820,23 @@ async fn run_interactive<W: UiWriter>(
} }
} }
// Display message if README was loaded // Display message if AGENTS.md or README was loaded
if readme_content.is_some() { if let Some(ref content) = combined_content {
// Extract the first heading or title from the README // Check what was loaded
let readme_snippet = if let Some(ref content) = readme_content { let has_agents = content.contains("Agent Configuration");
extract_readme_heading(content) let has_readme = content.contains("Project README");
.unwrap_or_else(|| "Project documentation loaded".to_string())
} else { if has_agents {
"Project documentation loaded".to_string() output.print("🤖 AGENTS.md configuration loaded");
}; }
if has_readme {
// Extract the first heading or title from the README
let readme_snippet = extract_readme_heading(content)
.unwrap_or_else(|| "Project documentation loaded".to_string());
output.print(&format!("📚 detected: {}", readme_snippet)); output.print(&format!("📚 detected: {}", readme_snippet));
}
} }
output.print(""); output.print("");

View File

@@ -250,7 +250,7 @@ impl TerminalState {
} }
/// Parse markdown and convert to styled lines /// Parse markdown and convert to styled lines
fn parse_markdown_line(&self, line: &str) -> Line { fn parse_markdown_line(&self, line: &str) -> Line<'_> {
// Skip parsing for special status lines to preserve their formatting // Skip parsing for special status lines to preserve their formatting
if line.starts_with("[SUCCESS]") || if line.starts_with("[SUCCESS]") ||
line.starts_with("[FAILED]") || line.starts_with("[FAILED]") ||

View File

@@ -17,6 +17,7 @@ mod tests {
"test prompt".to_string(), "test prompt".to_string(),
None, None,
100, 100,
false, // quiet parameter
); );
let result = retry_with_backoff( let result = retry_with_backoff(
@@ -55,6 +56,7 @@ mod tests {
"test prompt".to_string(), "test prompt".to_string(),
None, None,
100, 100,
false, // quiet parameter
); );
let result: Result<&str, _> = retry_with_backoff( let result: Result<&str, _> = retry_with_backoff(
@@ -87,6 +89,7 @@ mod tests {
"test prompt".to_string(), "test prompt".to_string(),
None, None,
100, 100,
false, // quiet parameter
); );
let result: Result<&str, _> = retry_with_backoff( let result: Result<&str, _> = retry_with_backoff(
@@ -118,6 +121,7 @@ mod tests {
long_prompt, long_prompt,
None, None,
100, 100,
false, // quiet parameter
); );
// The prompt should be truncated to 1000 chars // The prompt should be truncated to 1000 chars