From ee69403bdb41d6aa2ebfccd08f5d0fd00eb74221 Mon Sep 17 00:00:00 2001 From: Ryan Ward Date: Tue, 12 May 2026 10:43:25 -0500 Subject: [PATCH] Add suggest_next_prompt tool for Bedrock prompt suggestions --- app/Cargo.toml | 1 + app/src/ai/bedrock/convert_request.rs | 28 ++++++++++++++++++++++++++- app/src/ai/bedrock/stream.rs | 22 +++++++++++++++++++++ app/src/ai/bedrock/tool_docs.rs | 20 +++++++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/app/Cargo.toml b/app/Cargo.toml index bff560e4..1dc46456 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -495,6 +495,7 @@ default = [ "grep_tool", "validate_autosuggestions", "clear_autosuggestion_on_escape", + "prompt_suggestions_via_maa", "file_retrieval_tools", "mcp_server", "fast_forward_autoexecute_button", diff --git a/app/src/ai/bedrock/convert_request.rs b/app/src/ai/bedrock/convert_request.rs index d4af8437..12b8dd09 100644 --- a/app/src/ai/bedrock/convert_request.rs +++ b/app/src/ai/bedrock/convert_request.rs @@ -615,7 +615,8 @@ pub fn extract_system_prompt(request: &api::Request) -> Option { 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("- `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("- 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"] }), }, + "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 { name: name.to_string(), description: format!("Tool: {}", name), @@ -760,6 +773,7 @@ fn default_tool_definitions() -> Vec { tool_definition_for_name("apply_file_diffs"), tool_definition_for_name("grep"), 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(), 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!({})), } } else { diff --git a/app/src/ai/bedrock/stream.rs b/app/src/ai/bedrock/stream.rs index eca67ed6..f4ce6daf 100644 --- a/app/src/ai/bedrock/stream.rs +++ b/app/src/ai/bedrock/stream.rs @@ -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"); None diff --git a/app/src/ai/bedrock/tool_docs.rs b/app/src/ai/bedrock/tool_docs.rs index aaebbe96..de6a0414 100644 --- a/app/src/ai/bedrock/tool_docs.rs +++ b/app/src/ai/bedrock/tool_docs.rs @@ -184,6 +184,25 @@ Get detailed usage documentation for any available tool. ## 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."#; +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 { match tool_name { "capabilities" => Some(CAPABILITIES_DOC.to_string()), @@ -193,6 +212,7 @@ pub fn get_tool_documentation(tool_name: &str) -> Option { "grep" => Some(GREP_DOC.to_string()), "file_glob" => Some(FILE_GLOB_DOC.to_string()), "get_tool_documentation" => Some(GET_TOOL_DOCUMENTATION_DOC.to_string()), + "suggest_next_prompt" => Some(SUGGEST_NEXT_PROMPT_DOC.to_string()), _ => None, } }