Add agent-specific language prompt injection
When running in agent mode (e.g., --agent carmack) in a workspace with detected languages, inject agent+language-specific prompts from prompts/langs/<agent>.<lang>.md at the end of the system prompt. Changes: - Add AGENT_LANGUAGE_PROMPTS static array for compile-time embedding - Add get_agent_language_prompt() to look up specific agent+lang combos - Add get_agent_language_prompts_for_workspace_with_langs() that returns both content and matched languages for display - Update agent_mode.rs to inject prompts and show which languages loaded - Display format: '✓ carmack: racket language guidance' - Add tests for new functionality Uses the same detect_languages() mechanism as regular language prompts to avoid code-path aliasing.
This commit is contained in:
@@ -8,6 +8,7 @@ use g3_core::ui_writer::UiWriter;
|
||||
use g3_core::Agent;
|
||||
|
||||
use crate::project_files::{combine_project_content, read_agents_config, read_project_memory, read_project_readme};
|
||||
use crate::language_prompts::{get_language_prompts_for_workspace, get_agent_language_prompts_for_workspace_with_langs};
|
||||
use crate::simple_output::SimpleOutput;
|
||||
use crate::embedded_agents::load_agent_prompt;
|
||||
use crate::ui_writer_impl::ConsoleUiWriter;
|
||||
@@ -137,16 +138,38 @@ pub async fn run_agent_mode(
|
||||
"·"
|
||||
};
|
||||
output.print(&format!(
|
||||
" {} README | {} AGENTS.md | {} Memory",
|
||||
readme_status, agents_status, memory_status
|
||||
" {} README {} AGENTS.md {} Memory",
|
||||
readme_status, agents_status, memory_status,
|
||||
));
|
||||
|
||||
// Get language-specific prompts (same mechanism as normal mode)
|
||||
let language_content = get_language_prompts_for_workspace(&workspace_dir);
|
||||
|
||||
// Get agent+language-specific prompts (e.g., carmack.racket.md) and show which languages
|
||||
let detected_langs = crate::language_prompts::detect_languages(&workspace_dir);
|
||||
let agent_lang_content = if detected_langs.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let (content, matched_langs) = get_agent_language_prompts_for_workspace_with_langs(&workspace_dir, agent_name);
|
||||
for lang in matched_langs {
|
||||
output.print(&format!(" ✓ {}: {} language guidance", agent_name, lang));
|
||||
}
|
||||
content
|
||||
};
|
||||
|
||||
// Append agent+language-specific content to system prompt if available
|
||||
let system_prompt = if let Some(agent_lang) = agent_lang_content {
|
||||
format!("{}\n\n{}", system_prompt, agent_lang)
|
||||
} else {
|
||||
system_prompt
|
||||
};
|
||||
|
||||
// Combine all content for the agent's context
|
||||
let combined_content = combine_project_content(
|
||||
agents_content_opt,
|
||||
readme_content_opt,
|
||||
memory_content_opt,
|
||||
crate::language_prompts::get_language_prompts_for_workspace(&workspace_dir),
|
||||
language_content,
|
||||
&workspace_dir,
|
||||
);
|
||||
|
||||
|
||||
@@ -18,6 +18,13 @@ static LANGUAGE_PROMPTS: &[(&str, &[&str], &str)] = &[
|
||||
),
|
||||
];
|
||||
|
||||
/// Embedded agent-specific language prompts.
|
||||
/// Format: (agent_name, language_name, prompt_content)
|
||||
static AGENT_LANGUAGE_PROMPTS: &[(&str, &str, &str)] = &[
|
||||
// (agent_name, language_name, prompt_content)
|
||||
("carmack", "racket", include_str!("../../../prompts/langs/carmack.racket.md")),
|
||||
];
|
||||
|
||||
/// Detect languages present in the workspace by scanning for file extensions.
|
||||
/// Returns a list of detected language names.
|
||||
pub fn detect_languages(workspace_dir: &Path) -> Vec<&'static str> {
|
||||
@@ -118,6 +125,46 @@ pub fn list_available_languages() -> Vec<&'static str> {
|
||||
LANGUAGE_PROMPTS.iter().map(|(name, _, _)| *name).collect()
|
||||
}
|
||||
|
||||
/// Get agent-specific language prompt for a specific agent and language.
|
||||
pub fn get_agent_language_prompt(agent_name: &str, lang: &str) -> Option<&'static str> {
|
||||
AGENT_LANGUAGE_PROMPTS
|
||||
.iter()
|
||||
.find(|(agent, language, _)| *agent == agent_name && *language == lang)
|
||||
.map(|(_, _, content)| *content)
|
||||
}
|
||||
|
||||
/// Get agent-specific language prompts for detected languages in the workspace.
|
||||
/// Returns formatted content ready for injection into the agent's system prompt.
|
||||
#[allow(dead_code)]
|
||||
pub fn get_agent_language_prompts_for_workspace(
|
||||
workspace_dir: &Path,
|
||||
agent_name: &str,
|
||||
) -> Option<String> {
|
||||
let (content, _) = get_agent_language_prompts_for_workspace_with_langs(workspace_dir, agent_name);
|
||||
content
|
||||
}
|
||||
|
||||
/// Get agent-specific language prompts for detected languages in the workspace.
|
||||
/// Returns both the formatted content and the list of languages that had matching prompts.
|
||||
pub fn get_agent_language_prompts_for_workspace_with_langs(
|
||||
workspace_dir: &Path,
|
||||
agent_name: &str,
|
||||
) -> (Option<String>, Vec<&'static str>) {
|
||||
let detected = detect_languages(workspace_dir);
|
||||
let mut prompts = Vec::new();
|
||||
let mut matched_langs = Vec::new();
|
||||
|
||||
for lang in detected {
|
||||
if let Some(content) = get_agent_language_prompt(agent_name, lang) {
|
||||
prompts.push(content.to_string());
|
||||
matched_langs.push(lang);
|
||||
}
|
||||
}
|
||||
|
||||
let content = if prompts.is_empty() { None } else { Some(prompts.join("\n\n---\n\n")) };
|
||||
(content, matched_langs)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -166,4 +213,29 @@ mod tests {
|
||||
assert!(content.contains("🔧 Language-Specific Guidance"));
|
||||
assert!(content.contains("raco"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_carmack_racket_prompt_embedded() {
|
||||
let prompt = get_agent_language_prompt("carmack", "racket");
|
||||
assert!(prompt.is_some());
|
||||
assert!(prompt.unwrap().contains("RACKET-SPECIFIC GUIDANCE"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_agent_language_prompt_not_found() {
|
||||
let prompt = get_agent_language_prompt("nonexistent", "racket");
|
||||
assert!(prompt.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_agent_prompts_for_workspace() {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
let rkt_file = temp_dir.path().join("main.rkt");
|
||||
fs::write(&rkt_file, "#lang racket\n").unwrap();
|
||||
|
||||
let prompts = get_agent_language_prompts_for_workspace(temp_dir.path(), "carmack");
|
||||
assert!(prompts.is_some());
|
||||
let content = prompts.unwrap();
|
||||
assert!(content.contains("RACKET-SPECIFIC GUIDANCE"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user