Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions sidecar/src/agentic/tool/broker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ use super::{
reward::client::RewardClientGenerator,
search::big_search::BigSearchBroker,
session::{
ask_followup_question::AskFollowupQuestions, attempt_completion::AttemptCompletionClient,
chat::SessionChatClient, exchange::SessionExchangeClient,
hot_streak::SessionHotStreakClient,
ask_followup_question::AskFollowupQuestions, ask_expert::AskExpert,
attempt_completion::AttemptCompletionClient, chat::SessionChatClient,
exchange::SessionExchangeClient, hot_streak::SessionHotStreakClient,
},
swe_bench::test_tool::SWEBenchTestTool,
terminal::terminal::TerminalTool,
Expand Down Expand Up @@ -462,6 +462,10 @@ impl ToolBroker {
ToolType::AskFollowupQuestions,
Box::new(AskFollowupQuestions::new()),
);
tools.insert(
ToolType::AskExpert,
Box::new(AskExpert::new()),
);
tools.insert(
ToolType::AttemptCompletion,
Box::new(AttemptCompletionClient::new()),
Expand Down Expand Up @@ -609,4 +613,4 @@ impl ToolBroker {
}
}
}
}
}
18 changes: 17 additions & 1 deletion sidecar/src/agentic/tool/input.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::agentic::tool::session::ask_expert::AskExpertRequest;
use super::{
code_edit::{
code_editor::CodeEditorParameters,
Expand Down Expand Up @@ -97,6 +98,7 @@ pub enum ToolInputPartial {
LSPDiagnostics(WorkspaceDiagnosticsPartial),
TerminalCommand(TerminalInputPartial),
AskFollowupQuestions(AskFollowupQuestionsRequest),
AskExpert(AskExpertRequest),
AttemptCompletion(AttemptCompletionClientRequest),
RepoMapGeneration(RepoMapGeneratorRequestPartial),
TestRunner(TestRunnerRequestPartial),
Expand All @@ -119,6 +121,7 @@ impl ToolInputPartial {
Self::LSPDiagnostics(_) => ToolType::LSPDiagnostics,
Self::TerminalCommand(_) => ToolType::TerminalCommand,
Self::AskFollowupQuestions(_) => ToolType::AskFollowupQuestions,
Self::AskExpert(_) => ToolType::AskExpert,
Self::AttemptCompletion(_) => ToolType::AttemptCompletion,
Self::RepoMapGeneration(_) => ToolType::RepoMapGeneration,
Self::TestRunner(_) => ToolType::TestRunner,
Expand All @@ -143,6 +146,7 @@ impl ToolInputPartial {
Self::LSPDiagnostics(lsp_diagnostics) => lsp_diagnostics.to_string(),
Self::TerminalCommand(terminal_command) => terminal_command.to_string(),
Self::AskFollowupQuestions(ask_followup_question) => ask_followup_question.to_string(),
Self::AskExpert(ask_expert) => ask_expert.to_string(),
Self::AttemptCompletion(attempt_completion) => attempt_completion.to_string(),
Self::RepoMapGeneration(repo_map_generator) => repo_map_generator.to_string(),
Self::TestRunner(test_runner_partial_output) => test_runner_partial_output.to_string(),
Expand Down Expand Up @@ -197,6 +201,7 @@ impl ToolInputPartial {
serde_json::to_value(context_crunching).ok()
}
Self::McpTool(mcp_partial) => serde_json::to_value(mcp_partial).ok(),
Self::AskExpert(ask_expert) => serde_json::to_value(ask_expert).ok(),
}
}

Expand Down Expand Up @@ -330,6 +335,8 @@ pub enum ToolInput {
ListFiles(ListFilesInput),
// Ask the user some question
AskFollowupQuestions(AskFollowupQuestionsRequest),
// Ask an expert for help
AskExpert(AskExpertRequest),
// Attempt completion of a task
AttemptCompletion(AttemptCompletionClientRequest),
// Generates the repo map
Expand Down Expand Up @@ -431,6 +438,7 @@ impl ToolInput {
ToolInput::SearchFileContentWithRegex(_) => ToolType::SearchFileContentWithRegex,
ToolInput::ListFiles(_) => ToolType::ListFiles,
ToolInput::AskFollowupQuestions(_) => ToolType::AskFollowupQuestions,
ToolInput::AskExpert(_) => ToolType::AskExpert,
ToolInput::AttemptCompletion(_) => ToolType::AttemptCompletion,
ToolInput::RepoMapGeneration(_) => ToolType::RepoMapGeneration,
ToolInput::SubProcessSpawnedPendingOutput(_) => {
Expand Down Expand Up @@ -521,6 +529,14 @@ impl ToolInput {
}
}

pub fn is_ask_expert(self) -> Result<AskExpertRequest, ToolError> {
if let ToolInput::AskExpert(request) = self {
Ok(request)
} else {
Err(ToolError::WrongToolInput(ToolType::AskExpert))
}
}

pub fn is_list_files(self) -> Result<ListFilesInput, ToolError> {
if let ToolInput::ListFiles(request) = self {
Ok(request)
Expand Down Expand Up @@ -1202,4 +1218,4 @@ impl ToolInput {
Err(ToolError::WrongToolInput(ToolType::RequestScreenshot))
}
}
}
}
8 changes: 7 additions & 1 deletion sidecar/src/agentic/tool/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ use super::{
rerank::base::ReRankEntriesForBroker,
reward::client::RewardGenerationResponse,
session::{
ask_expert::AskExpertResponse,
ask_followup_question::AskFollowupQuestionsResponse,
attempt_completion::AttemptCompletionClientResponse, chat::SessionChatClientResponse,
exchange::SessionExchangeNewResponse, hot_streak::SessionHotStreakResponse,
Expand Down Expand Up @@ -235,6 +236,8 @@ pub enum ToolOutput {
FindFiles(FindFilesResponse),
// Request screenshot output
RequestScreenshot(RequestScreenshotOutput),
// Ask expert response
AskExpert(AskExpertResponse),
// dynamically configured MCP servers
McpTool(McpToolResponse),
}
Expand Down Expand Up @@ -391,6 +394,9 @@ impl ToolOutput {
pub fn go_to_reference(refernece: GoToReferencesResponse) -> Self {
ToolOutput::GoToReference(refernece)
}
pub fn ask_expert(response: AskExpertResponse) -> Self {
ToolOutput::AskExpert(response)
}

pub fn code_correctness_action(output: CodeCorrectnessAction) -> Self {
ToolOutput::CodeCorrectnessAction(output)
Expand Down Expand Up @@ -932,4 +938,4 @@ impl ToolOutput {
}

impl_output!(get_mcp_response, McpTool, McpToolResponse);
}
}
94 changes: 94 additions & 0 deletions sidecar/src/agentic/tool/session/ask_expert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! Allows the agent to ask an expert for help or clarification

use async_trait::async_trait;

use crate::agentic::tool::{
errors::ToolError,
input::ToolInput,
output::ToolOutput,
r#type::{Tool, ToolRewardScale},
};

pub struct AskExpert {}

impl AskExpert {
pub fn new() -> Self {
Self {}
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AskExpertRequest {
question: String,
}

impl AskExpertRequest {
pub fn new(question: String) -> Self {
Self { question }
}

pub fn question(&self) -> &str {
&self.question
}

pub fn to_string(&self) -> String {
format!(
r#"<ask_expert>
<question>
{}
</question>
</ask_expert>"#,
self.question
)
}
}

#[derive(Debug, Clone)]
pub struct AskExpertResponse {
expert_question: String,
}

impl AskExpertResponse {
pub fn expert_question(&self) -> &str {
&self.expert_question
}
}

impl AskExpertResponse {
pub fn new(expert_question: String) -> Self {
Self { expert_question }
}
}

#[async_trait]
impl Tool for AskExpert {
async fn invoke(&self, input: ToolInput) -> Result<ToolOutput, ToolError> {
let context = input.is_ask_expert()?;
let response = AskExpertResponse::new(context.question);
Ok(ToolOutput::ask_expert(response))
}

fn tool_description(&self) -> String {
r#"### ask_expert
Ask an expert for help or clarification when facing a difficult problem or when you need specialized knowledge. This tool allows the agent to request assistance from a domain expert when it encounters complex issues, feels stuck, or needs guidance on a challenging task. Use this tool when you need insights that go beyond your current capabilities or when you need validation for a proposed approach."#.to_owned()
}

fn tool_input_format(&self) -> String {
r#"Parameters:
- question: (required) The question or request for the expert. This should clearly explain the problem you're facing and what kind of expertise you need.
Usage:
<ask_expert>
<question>
Your question for the expert here
</question>
</ask_expert>"#.to_owned()
}

fn get_evaluation_criteria(&self, _trajectory_length: usize) -> Vec<String> {
vec![]
}

fn get_reward_scale(&self, _trajectory_length: usize) -> Vec<ToolRewardScale> {
vec![]
}
}
3 changes: 2 additions & 1 deletion sidecar/src/agentic/tool/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
//! This keeps track of all the different type of edits which we are going to be
//! working on top of

pub mod ask_expert;
pub mod ask_followup_question;
pub mod attempt_completion;
pub(crate) mod chat;
pub(crate) mod exchange;
pub(crate) mod hot_streak;
pub mod service;
pub mod session;
pub mod tool_use_agent;
pub mod tool_use_agent;
1 change: 1 addition & 0 deletions sidecar/src/agentic/tool/session/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,7 @@ impl SessionService {
tool_type.to_string().bright_white().to_string()
}
ToolInputPartial::McpTool(_) => tool_type.to_string().cyan().to_string(),
ToolInputPartial::AskExpert(_) => tool_type.to_string().bright_white().to_string(),
};
state_params.push(tool_str);
}
Expand Down
3 changes: 3 additions & 0 deletions sidecar/src/agentic/tool/session/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3125,6 +3125,9 @@ reason: {}"#,
exchange_id.to_owned(),
);
}
ToolInputPartial::AskExpert(ask_expert) => {
println!("ask expert: {}", ask_expert.to_string());
}
}
Ok(self)
}
Expand Down
10 changes: 5 additions & 5 deletions sidecar/src/agentic/tool/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ pub enum ToolType {
// code editing warmup tool
CodeEditingWarmupTool,
// grab outline nodes using the editor
// Ask an expert for help
AskExpert,
OutlineNodesUsingEditor,
// filters references
ReferencesFilter,
Expand Down Expand Up @@ -243,14 +245,12 @@ impl std::fmt::Display for ToolType {
ToolType::ContextDrivenChatReply => write!(f, "Context driven chat reply"),
ToolType::NewExchangeDuringSession => write!(f, "New exchange during session"),
ToolType::UndoChangesMadeDuringSession => write!(f, "Undo changes made during session"),
ToolType::ContextDriveHotStreakReply => write!(
f,
"Context driven hot streak reply which looks at things out of scope"
),
ToolType::ContextDriveHotStreakReply => write!(f, "Context drive hot streak reply"),
ToolType::TerminalCommand => write!(f, "execute_command"),
ToolType::SearchFileContentWithRegex => write!(f, "search_files"),
ToolType::ListFiles => write!(f, "list_files"),
ToolType::AskFollowupQuestions => write!(f, "ask_followup_question"),
ToolType::AskExpert => write!(f, "ask_expert"),
ToolType::AttemptCompletion => write!(f, "attempt_completion"),
ToolType::RepoMapGeneration => write!(f, "repo_map_generation"),
ToolType::SubProcessSpawnedPendingOutput => {
Expand Down Expand Up @@ -342,4 +342,4 @@ pub trait Tool {

/// Gets the reward scaling after the tool has been used
fn get_reward_scale(&self, trajectory_length: usize) -> Vec<ToolRewardScale>;
}
}
3 changes: 2 additions & 1 deletion sidecar/src/mcts/action_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2008,6 +2008,7 @@ impl SearchTree {
ToolInputPartial::RequestScreenshot(_) => {
tool_type.to_string().bright_white().to_string()
}
ToolInputPartial::AskExpert(_) => tool_type.to_string().bright_white().to_string(),
ToolInputPartial::McpTool(_) => tool_type.to_string().cyan().to_string(),
};
state_params.push(tool_str);
Expand Down Expand Up @@ -2165,4 +2166,4 @@ where
map_serializer.serialize_entry(&k.to_string(), v)?;
}
map_serializer.end()
}
}
3 changes: 2 additions & 1 deletion sidecar/src/mcts/execution/inference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,7 @@ Output:
}
}
ToolInputPartial::RequestScreenshot(_) => Err(InferenceError::WrongToolOutput),
ToolInputPartial::AskExpert(_) => Err(InferenceError::WrongToolOutput),
}
}
}
}