From e65bd6168335a989730d00212053425feaf52691 Mon Sep 17 00:00:00 2001 From: "Dhanji R. Prasanna" Date: Mon, 12 Jan 2026 18:27:29 +0530 Subject: [PATCH] Inject working directory into context to prevent path hallucinations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LLM often hallucinates incorrect paths like /Users/jnbrymn/GitHub/g3 when the actual working directory is different. This causes wasted tokens and failed commands as the LLM tries cd commands that fail. Fix: Add the current working directory to the combined project content that gets injected into the context at startup. This appears as: 📂 Working Directory: /actual/path/to/workspace This is prepended before AGENTS.md, README.md, and project memory, so the LLM knows the correct path from the start. --- crates/g3-cli/src/agent_mode.rs | 1 + crates/g3-cli/src/lib.rs | 2 +- crates/g3-cli/src/project_files.rs | 31 ++++++++++++++++++++++++------ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/crates/g3-cli/src/agent_mode.rs b/crates/g3-cli/src/agent_mode.rs index a6f5c0e..1bb9a39 100644 --- a/crates/g3-cli/src/agent_mode.rs +++ b/crates/g3-cli/src/agent_mode.rs @@ -181,6 +181,7 @@ pub async fn run_agent_mode( agents_content_opt, readme_content_opt, memory_content_opt, + &workspace_dir, ); // Create agent with custom system prompt diff --git a/crates/g3-cli/src/lib.rs b/crates/g3-cli/src/lib.rs index 87559f8..fac3dab 100644 --- a/crates/g3-cli/src/lib.rs +++ b/crates/g3-cli/src/lib.rs @@ -106,7 +106,7 @@ pub async fn run() -> Result<()> { let config = load_config_with_cli_overrides(&cli)?; // Combine AGENTS.md, README, and memory content - let combined_content = combine_project_content(agents_content, readme_content, memory_content); + let combined_content = combine_project_content(agents_content, readme_content, memory_content, &workspace_dir); run_console_mode(cli, config, project, combined_content, workspace_dir).await } diff --git a/crates/g3-cli/src/project_files.rs b/crates/g3-cli/src/project_files.rs index 3e26d00..d13318e 100644 --- a/crates/g3-cli/src/project_files.rs +++ b/crates/g3-cli/src/project_files.rs @@ -85,12 +85,17 @@ pub fn read_project_memory(workspace_dir: &Path) -> Option { /// Combine AGENTS.md, README, and memory content into a single string. /// /// Returns None if all inputs are None, otherwise joins non-None parts with double newlines. +/// Prepends the current working directory to help the LLM avoid path hallucinations. pub fn combine_project_content( agents_content: Option, readme_content: Option, memory_content: Option, + workspace_dir: &Path, ) -> Option { - let parts: Vec = [agents_content, readme_content, memory_content] + // Always include working directory to prevent LLM from hallucinating paths + let cwd_info = format!("📂 Working Directory: {}", workspace_dir.display()); + + let parts: Vec = [Some(cwd_info), agents_content, readme_content, memory_content] .into_iter() .flatten() .collect(); @@ -201,23 +206,37 @@ mod tests { #[test] fn test_combine_project_content_all_some() { + let workspace = std::path::PathBuf::from("/test/workspace"); let result = combine_project_content( Some("agents".to_string()), Some("readme".to_string()), Some("memory".to_string()), + &workspace, ); - assert_eq!(result, Some("agents\n\nreadme\n\nmemory".to_string())); + assert!(result.is_some()); + let content = result.unwrap(); + assert!(content.contains("📂 Working Directory: /test/workspace")); + assert!(content.contains("agents")); + assert!(content.contains("readme")); + assert!(content.contains("memory")); } #[test] fn test_combine_project_content_partial() { - let result = combine_project_content(None, Some("readme".to_string()), None); - assert_eq!(result, Some("readme".to_string())); + let workspace = std::path::PathBuf::from("/test/workspace"); + let result = combine_project_content(None, Some("readme".to_string()), None, &workspace); + assert!(result.is_some()); + let content = result.unwrap(); + assert!(content.contains("📂 Working Directory: /test/workspace")); + assert!(content.contains("readme")); } #[test] fn test_combine_project_content_all_none() { - let result = combine_project_content(None, None, None); - assert_eq!(result, None); + let workspace = std::path::PathBuf::from("/test/workspace"); + let result = combine_project_content(None, None, None, &workspace); + // Now always returns Some because we always include the working directory + assert!(result.is_some()); + assert!(result.unwrap().contains("📂 Working Directory: /test/workspace")); } }