Inject working directory into context to prevent path hallucinations
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.
This commit is contained in:
@@ -181,6 +181,7 @@ pub async fn run_agent_mode(
|
|||||||
agents_content_opt,
|
agents_content_opt,
|
||||||
readme_content_opt,
|
readme_content_opt,
|
||||||
memory_content_opt,
|
memory_content_opt,
|
||||||
|
&workspace_dir,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create agent with custom system prompt
|
// Create agent with custom system prompt
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ pub async fn run() -> Result<()> {
|
|||||||
let config = load_config_with_cli_overrides(&cli)?;
|
let config = load_config_with_cli_overrides(&cli)?;
|
||||||
|
|
||||||
// Combine AGENTS.md, README, and memory content
|
// 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
|
run_console_mode(cli, config, project, combined_content, workspace_dir).await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,12 +85,17 @@ pub fn read_project_memory(workspace_dir: &Path) -> Option<String> {
|
|||||||
/// Combine AGENTS.md, README, and memory content into a single string.
|
/// 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.
|
/// 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(
|
pub fn combine_project_content(
|
||||||
agents_content: Option<String>,
|
agents_content: Option<String>,
|
||||||
readme_content: Option<String>,
|
readme_content: Option<String>,
|
||||||
memory_content: Option<String>,
|
memory_content: Option<String>,
|
||||||
|
workspace_dir: &Path,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let parts: Vec<String> = [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<String> = [Some(cwd_info), agents_content, readme_content, memory_content]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect();
|
.collect();
|
||||||
@@ -201,23 +206,37 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_combine_project_content_all_some() {
|
fn test_combine_project_content_all_some() {
|
||||||
|
let workspace = std::path::PathBuf::from("/test/workspace");
|
||||||
let result = combine_project_content(
|
let result = combine_project_content(
|
||||||
Some("agents".to_string()),
|
Some("agents".to_string()),
|
||||||
Some("readme".to_string()),
|
Some("readme".to_string()),
|
||||||
Some("memory".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]
|
#[test]
|
||||||
fn test_combine_project_content_partial() {
|
fn test_combine_project_content_partial() {
|
||||||
let result = combine_project_content(None, Some("readme".to_string()), None);
|
let workspace = std::path::PathBuf::from("/test/workspace");
|
||||||
assert_eq!(result, Some("readme".to_string()));
|
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]
|
#[test]
|
||||||
fn test_combine_project_content_all_none() {
|
fn test_combine_project_content_all_none() {
|
||||||
let result = combine_project_content(None, None, None);
|
let workspace = std::path::PathBuf::from("/test/workspace");
|
||||||
assert_eq!(result, None);
|
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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user