Add suggest_next_prompt tool for Bedrock prompt suggestions

This commit is contained in:
Ryan Ward
2026-05-12 10:43:25 -05:00
parent e13ed355f6
commit ee69403bdb
4 changed files with 70 additions and 1 deletions
+1
View File
@@ -495,6 +495,7 @@ default = [
"grep_tool", "grep_tool",
"validate_autosuggestions", "validate_autosuggestions",
"clear_autosuggestion_on_escape", "clear_autosuggestion_on_escape",
"prompt_suggestions_via_maa",
"file_retrieval_tools", "file_retrieval_tools",
"mcp_server", "mcp_server",
"fast_forward_autoexecute_button", "fast_forward_autoexecute_button",
+27 -1
View File
@@ -615,7 +615,8 @@ pub fn extract_system_prompt(request: &api::Request) -> Option<String> {
prompt.push_str("- `apply_file_diffs`: Apply search/replace edits to files.\n"); prompt.push_str("- `apply_file_diffs`: Apply search/replace edits to files.\n");
prompt.push_str("- `grep`: Search for patterns in files. Pass all patterns in one call.\n"); prompt.push_str("- `grep`: Search for patterns in files. Pass all patterns in one call.\n");
prompt.push_str("- `file_glob`: Find files matching glob patterns. Pass all patterns in one call.\n"); prompt.push_str("- `file_glob`: Find files matching glob patterns. Pass all patterns in one call.\n");
prompt.push_str("- `get_tool_documentation`: Get detailed documentation for any tool or system capabilities.\n\n"); prompt.push_str("- `get_tool_documentation`: Get detailed documentation for any tool or system capabilities.\n");
prompt.push_str("- `suggest_next_prompt`: After completing a task, suggest a follow-up action the user might want.\n\n");
prompt.push_str("## Guidelines\n"); prompt.push_str("## Guidelines\n");
prompt.push_str("- ALWAYS use tools to explore the codebase before answering questions about code.\n"); prompt.push_str("- ALWAYS use tools to explore the codebase before answering questions about code.\n");
@@ -742,6 +743,18 @@ fn tool_definition_for_name(name: &str) -> ToolDefinition {
"required": ["patterns"] "required": ["patterns"]
}), }),
}, },
"suggest_next_prompt" => ToolDefinition {
name: "suggest_next_prompt".to_string(),
description: "After completing a task, suggest a relevant follow-up prompt the user might want to try next. Use this to suggest a natural next step based on what was just accomplished.".to_string(),
input_schema: serde_json::json!({
"type": "object",
"properties": {
"prompt": { "type": "string", "description": "The suggested prompt text that will be sent to the agent if the user accepts" },
"label": { "type": "string", "description": "Short display label for the suggestion chip (keep under 40 chars)" }
},
"required": ["prompt", "label"]
}),
},
_ => ToolDefinition { _ => ToolDefinition {
name: name.to_string(), name: name.to_string(),
description: format!("Tool: {}", name), description: format!("Tool: {}", name),
@@ -760,6 +773,7 @@ fn default_tool_definitions() -> Vec<ToolDefinition> {
tool_definition_for_name("apply_file_diffs"), tool_definition_for_name("apply_file_diffs"),
tool_definition_for_name("grep"), tool_definition_for_name("grep"),
tool_definition_for_name("file_glob"), tool_definition_for_name("file_glob"),
tool_definition_for_name("suggest_next_prompt"),
] ]
} }
@@ -832,6 +846,18 @@ fn extract_tool_call_info(tool_call: &api::message::ToolCall) -> (String, serde_
"file_glob".to_string(), "file_glob".to_string(),
serde_json::json!({ "patterns": glob.patterns }), serde_json::json!({ "patterns": glob.patterns }),
), ),
api::message::tool_call::Tool::SuggestPrompt(sp) => {
let (prompt, label) = match &sp.display_mode {
Some(api::message::tool_call::suggest_prompt::DisplayMode::PromptChip(chip)) => {
(chip.prompt.clone(), chip.label.clone())
}
_ => (String::new(), String::new()),
};
(
"suggest_next_prompt".to_string(),
serde_json::json!({ "prompt": prompt, "label": label }),
)
}
_ => ("unknown_tool".to_string(), serde_json::json!({})), _ => ("unknown_tool".to_string(), serde_json::json!({})),
} }
} else { } else {
+22
View File
@@ -588,6 +588,28 @@ fn build_tool_call_message(
}, },
)) ))
} }
"suggest_next_prompt" => {
let prompt = input
.get("prompt")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
let label = input
.get("label")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
Some(api::message::tool_call::Tool::SuggestPrompt(
api::message::tool_call::SuggestPrompt {
is_trigger_irrelevant: false,
display_mode: Some(
api::message::tool_call::suggest_prompt::DisplayMode::PromptChip(
api::message::tool_call::suggest_prompt::PromptChip { prompt, label },
),
),
},
))
}
_ => { _ => {
log::warn!("[bedrock] Unknown tool name: {tool_name}, emitting as text"); log::warn!("[bedrock] Unknown tool name: {tool_name}, emitting as text");
None None
+20
View File
@@ -184,6 +184,25 @@ Get detailed usage documentation for any available tool.
## When to use ## When to use
Call this tool when you need detailed guidance on how to use a specific tool effectively, especially for complex operations like file editing or understanding the permission model."#; Call this tool when you need detailed guidance on how to use a specific tool effectively, especially for complex operations like file editing or understanding the permission model."#;
const SUGGEST_NEXT_PROMPT_DOC: &str = r#"# suggest_next_prompt
Suggest a follow-up action the user might want after completing the current task.
## When to Use
- After completing a task successfully
- When there's a natural next step (e.g., "run tests" after writing code, "commit changes" after editing files)
- Only call this ONCE at the end of your response, alongside your final text output
## Parameters
- `prompt`: The full prompt text that will be sent to the agent if the user clicks the suggestion
- `label`: A short display label (under 40 characters) shown as a clickable chip
## Guidelines
- Keep labels concise and action-oriented (e.g., "Run tests", "Commit changes", "Deploy")
- The prompt should be specific enough to be useful without further clarification
- Only suggest actions that are relevant to what was just accomplished
- Do NOT suggest prompts when the conversation is exploratory or the user is asking questions"#;
pub fn get_tool_documentation(tool_name: &str) -> Option<String> { pub fn get_tool_documentation(tool_name: &str) -> Option<String> {
match tool_name { match tool_name {
"capabilities" => Some(CAPABILITIES_DOC.to_string()), "capabilities" => Some(CAPABILITIES_DOC.to_string()),
@@ -193,6 +212,7 @@ pub fn get_tool_documentation(tool_name: &str) -> Option<String> {
"grep" => Some(GREP_DOC.to_string()), "grep" => Some(GREP_DOC.to_string()),
"file_glob" => Some(FILE_GLOB_DOC.to_string()), "file_glob" => Some(FILE_GLOB_DOC.to_string()),
"get_tool_documentation" => Some(GET_TOOL_DOCUMENTATION_DOC.to_string()), "get_tool_documentation" => Some(GET_TOOL_DOCUMENTATION_DOC.to_string()),
"suggest_next_prompt" => Some(SUGGEST_NEXT_PROMPT_DOC.to_string()),
_ => None, _ => None,
} }
} }