feat: add /plan command in CLI to invoke reasoner with plan system prompt (#1616)

This commit is contained in:
Salman Mohammed
2025-03-20 10:10:01 -04:00
committed by GitHub
parent 3a4866cb7d
commit e273f8ebce
10 changed files with 369 additions and 51 deletions
+3
View File
@@ -63,6 +63,9 @@ pub trait Agent: Send + Sync {
/// Returns the prompt text that would be used as user input
async fn get_prompt(&self, name: &str, arguments: Value) -> Result<GetPromptResult>;
/// Get the plan prompt, which will be used with the planner (reasoner) model
async fn get_plan_prompt(&self) -> anyhow::Result<String>;
/// Get a reference to the provider used by this agent
async fn provider(&self) -> Arc<Box<dyn Provider>>;
}
+17 -1
View File
@@ -10,7 +10,7 @@ use std::time::Duration;
use tokio::sync::Mutex;
use tracing::{debug, instrument};
use super::extension::{ExtensionConfig, ExtensionError, ExtensionInfo, ExtensionResult};
use super::extension::{ExtensionConfig, ExtensionError, ExtensionInfo, ExtensionResult, ToolInfo};
use crate::config::Config;
use crate::prompt_template;
use crate::providers::base::Provider;
@@ -83,6 +83,14 @@ fn normalize(input: String) -> String {
result.to_lowercase()
}
pub fn get_parameter_names(tool: &Tool) -> Vec<String> {
tool.input_schema
.get("properties")
.and_then(|props| props.as_object())
.map(|props| props.keys().cloned().collect())
.unwrap_or_default()
}
impl Capabilities {
/// Create a new Capabilities with the specified provider
pub fn new(provider: Box<dyn Provider>) -> Self {
@@ -296,6 +304,14 @@ impl Capabilities {
Ok(result)
}
/// Get the extension prompt including client instructions
pub async fn get_planning_prompt(&self, tools_info: Vec<ToolInfo>) -> String {
let mut context: HashMap<&str, Value> = HashMap::new();
context.insert("tools", serde_json::to_value(tools_info).unwrap());
prompt_template::render_global_file("plan.md", &context).expect("Prompt should render")
}
/// Get the extension prompt including client instructions
pub async fn get_system_prompt(&self) -> String {
let mut context: HashMap<&str, Value> = HashMap::new();
+18
View File
@@ -192,3 +192,21 @@ impl ExtensionInfo {
}
}
}
/// Information about the tool used for building prompts
#[derive(Clone, Debug, Serialize)]
pub struct ToolInfo {
name: String,
description: String,
parameters: Vec<String>,
}
impl ToolInfo {
pub fn new(name: &str, description: &str, parameters: Vec<String>) -> Self {
Self {
name: name.to_string(),
description: description.to_string(),
parameters,
}
}
}
+15
View File
@@ -8,6 +8,8 @@ use tokio::sync::Mutex;
use tracing::{debug, instrument};
use super::agent::SessionConfig;
use super::capabilities::get_parameter_names;
use super::extension::ToolInfo;
use super::Agent;
use crate::agents::capabilities::Capabilities;
use crate::agents::extension::{ExtensionConfig, ExtensionResult};
@@ -243,6 +245,19 @@ impl Agent for ReferenceAgent {
Err(anyhow!("Prompt '{}' not found", name))
}
async fn get_plan_prompt(&self) -> anyhow::Result<String> {
let mut capabilities = self.capabilities.lock().await;
let tools = capabilities.get_prefixed_tools().await?;
let tools_info = tools
.into_iter()
.map(|tool| ToolInfo::new(&tool.name, &tool.description, get_parameter_names(&tool)))
.collect();
let plan_prompt = capabilities.get_planning_prompt(tools_info).await;
Ok(plan_prompt)
}
async fn provider(&self) -> Arc<Box<dyn Provider>> {
let capabilities = self.capabilities.lock().await;
capabilities.provider()
+15
View File
@@ -10,7 +10,9 @@ use tokio::sync::Mutex;
use tracing::{debug, error, instrument, warn};
use super::agent::SessionConfig;
use super::capabilities::get_parameter_names;
use super::detect_read_only_tools;
use super::extension::ToolInfo;
use super::Agent;
use crate::agents::capabilities::Capabilities;
use crate::agents::extension::{ExtensionConfig, ExtensionResult};
@@ -457,6 +459,19 @@ impl Agent for SummarizeAgent {
Err(anyhow!("Prompt '{}' not found", name))
}
async fn get_plan_prompt(&self) -> anyhow::Result<String> {
let mut capabilities = self.capabilities.lock().await;
let tools = capabilities.get_prefixed_tools().await?;
let tools_info = tools
.into_iter()
.map(|tool| ToolInfo::new(&tool.name, &tool.description, get_parameter_names(&tool)))
.collect();
let plan_prompt = capabilities.get_planning_prompt(tools_info).await;
Ok(plan_prompt)
}
async fn provider(&self) -> Arc<Box<dyn Provider>> {
let capabilities = self.capabilities.lock().await;
capabilities.provider()
+15 -1
View File
@@ -10,8 +10,9 @@ use tracing::{debug, error, instrument, warn};
use super::agent::SessionConfig;
use super::detect_read_only_tools;
use super::extension::ToolInfo;
use super::Agent;
use crate::agents::capabilities::Capabilities;
use crate::agents::capabilities::{get_parameter_names, Capabilities};
use crate::agents::extension::{ExtensionConfig, ExtensionResult};
use crate::agents::ToolPermissionStore;
use crate::config::Config;
@@ -511,6 +512,19 @@ impl Agent for TruncateAgent {
Err(anyhow!("Prompt '{}' not found", name))
}
async fn get_plan_prompt(&self) -> anyhow::Result<String> {
let mut capabilities = self.capabilities.lock().await;
let tools = capabilities.get_prefixed_tools().await?;
let tools_info = tools
.into_iter()
.map(|tool| ToolInfo::new(&tool.name, &tool.description, get_parameter_names(&tool)))
.collect();
let plan_prompt = capabilities.get_planning_prompt(tools_info).await;
Ok(plan_prompt)
}
async fn provider(&self) -> Arc<Box<dyn Provider>> {
let capabilities = self.capabilities.lock().await;
capabilities.provider()