feat: async research tool - runs in background, returns immediately
The research tool now spawns the scout agent in a background tokio task and returns immediately with a research_id placeholder. This allows the agent to continue working while research runs (30-120 seconds). Key changes: - New PendingResearchManager for tracking async research tasks - research tool returns immediately with placeholder containing research_id - research_status tool to check progress of pending research - Auto-injection of completed research at natural break points: - Start of each tool iteration (before LLM call) - Before prompting user in interactive mode - /research CLI command to list all research tasks - Updated system prompt to explain async behavior The agent can: - Continue with other work while research runs - Check status with research_status tool - Yield turn to user if results are critical before continuing
This commit is contained in:
@@ -38,6 +38,7 @@ pub async fn handle_command<W: UiWriter>(
|
||||
output.print(" /fragments - List dehydrated context fragments (ACD)");
|
||||
output.print(" /rehydrate - Restore a dehydrated fragment by ID");
|
||||
output.print(" /resume - List and switch to a previous session");
|
||||
output.print(" /research - List pending/completed research tasks");
|
||||
output.print(" /project <path> - Load a project from the given absolute path");
|
||||
output.print(" /unproject - Unload the current project and reset context");
|
||||
output.print(" /dump - Dump entire context window to file for debugging");
|
||||
@@ -130,6 +131,42 @@ pub async fn handle_command<W: UiWriter>(
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
"/research" => {
|
||||
let manager = agent.get_pending_research_manager();
|
||||
let all_tasks = manager.list_all();
|
||||
|
||||
if all_tasks.is_empty() {
|
||||
output.print("📋 No research tasks (pending or completed).");
|
||||
} else {
|
||||
output.print(&format!("📋 Research Tasks ({} total):\n", all_tasks.len()));
|
||||
|
||||
for task in all_tasks {
|
||||
let status_emoji = match task.status {
|
||||
g3_core::pending_research::ResearchStatus::Pending => "🔄",
|
||||
g3_core::pending_research::ResearchStatus::Complete => "✅",
|
||||
g3_core::pending_research::ResearchStatus::Failed => "❌",
|
||||
};
|
||||
|
||||
let injected_marker = if task.injected { " (injected)" } else { "" };
|
||||
|
||||
output.print(&format!(
|
||||
" {} `{}` - {} ({}){}\n Query: {}",
|
||||
status_emoji,
|
||||
task.id,
|
||||
task.status,
|
||||
task.elapsed_display(),
|
||||
injected_marker,
|
||||
if task.query.len() > 60 {
|
||||
format!("{}...", &task.query.chars().take(57).collect::<String>())
|
||||
} else {
|
||||
task.query.clone()
|
||||
}
|
||||
));
|
||||
output.print("");
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
cmd if cmd.starts_with("/run") => {
|
||||
let parts: Vec<&str> = cmd.splitn(2, ' ').collect();
|
||||
if parts.len() < 2 || parts[1].trim().is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user