Skip to content

Commit

Permalink
Merge pull request #1647 from codestoryai/features/scaffolding-for-to…
Browse files Browse the repository at this point in the history
…ol-agent

[sidecar] scaffolding for tool agent
  • Loading branch information
theskcd authored Dec 18, 2024
2 parents 610ccb5 + 76e423e commit 03e811b
Show file tree
Hide file tree
Showing 7 changed files with 657 additions and 53 deletions.
6 changes: 6 additions & 0 deletions sidecar/src/agentic/symbol/identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ impl LLMProperties {
self.llm = LLMType::GeminiPro;
self
}

/// Only allow tool use when we are using anthropic since open-router does not
/// support the str_replace_editor tool natively
pub fn supports_midwit_and_tool_use(&self) -> bool {
self.llm() == &LLMType::ClaudeSonnet && matches!(&self.provider, &LLMProvider::Anthropic)
}
}

#[derive(Debug, Clone, Eq, PartialEq, std::hash::Hash, serde::Serialize)]
Expand Down
10 changes: 10 additions & 0 deletions sidecar/src/agentic/tool/session/chat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,16 @@ impl SessionChatMessage {
}
}

pub fn insert_tool_return_value(mut self, tool_return: SessionChatToolReturn) -> Self {
self.tool_return.push(tool_return);
self
}

pub fn insert_tool_use(mut self, tool_use: SessionChatToolUse) -> Self {
self.tool_use.push(tool_use);
self
}

pub fn message(&self) -> &str {
&self.message
}
Expand Down
148 changes: 148 additions & 0 deletions sidecar/src/agentic/tool/session/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ impl SessionService {
tool_box: Arc<ToolBox>,
llm_broker: Arc<LLMBroker>,
user_context: UserContext,
is_midwit_tool_agent: bool,
mut message_properties: SymbolEventMessageProperties,
) -> Result<(), SymbolError> {
println!("session_service::tool_use_agentic::start");
Expand Down Expand Up @@ -682,6 +683,153 @@ impl SessionService {
Ok(())
}

/// Use the tool based json mode over here
async fn tool_use_midwit_json_mode(
&self,
mut session: Session,
session_id: String,
storage_path: String,
user_message: String,
exchange_id: String,
all_files: Vec<String>,
open_files: Vec<String>,
shell: String,
project_labels: Vec<String>,
repo_ref: RepoRef,
root_directory: String,
tool_box: Arc<ToolBox>,
llm_broker: Arc<LLMBroker>,
user_context: UserContext,
is_midwit_tool_agent: bool,
mut message_properties: SymbolEventMessageProperties,
) -> Result<(), SymbolError> {
// os can be passed over here safely since we can assume the sidecar is running
// close to the vscode server
// we should ideally get this information from the vscode-server side setting
let tool_agent = ToolUseAgent::new(
llm_broker.clone(),
root_directory.to_owned(),
std::env::consts::OS.to_owned(),
shell.to_owned(),
None,
);

session = session.human_message_tool_use(
exchange_id.to_owned(),
user_message.to_owned(),
all_files,
open_files,
shell,
user_context,
);
let _ = self.save_to_storage(&session).await;

session = session.accept_open_exchanges_if_any(message_properties.clone());
let mut human_message_ticker = 0;
// now that we have saved it we can start the loop over here and look out for the cancellation
// token which will imply that we should end the current loop
loop {
let _ = self.save_to_storage(&session).await;
let tool_exchange_id = self
.tool_box
.create_new_exchange(session_id.to_owned(), message_properties.clone())
.await?;

println!("tool_exchange_id::({:?})", &tool_exchange_id);

let cancellation_token = tokio_util::sync::CancellationToken::new();

message_properties = message_properties
.set_request_id(tool_exchange_id.to_owned())
.set_cancellation_token(cancellation_token.clone());

// track the new exchange over here
self.track_exchange(&session_id, &tool_exchange_id, cancellation_token.clone())
.await;

let tool_use_output = session
// the clone here is pretty bad but its the easiest and the sanest
// way to keep things on the happy path
.clone()
.get_tool_to_use(
tool_box.clone(),
tool_exchange_id.to_owned(),
exchange_id.to_owned(),
tool_agent.clone(),
message_properties.clone(),
)
.await;

println!("tool_use_output::{:?}", tool_use_output);

match tool_use_output {
Ok(AgentToolUseOutput::Success((tool_input_partial, new_session))) => {
// update our session
session = new_session;
// store to disk
let _ = self.save_to_storage(&session).await;
let tool_type = tool_input_partial.to_tool_type();
session = session
.invoke_tool(
tool_type.clone(),
tool_input_partial,
tool_box.clone(),
root_directory.to_owned(),
message_properties.clone(),
)
.await?;

let _ = self.save_to_storage(&session).await;
if matches!(tool_type, ToolType::AskFollowupQuestions)
|| matches!(tool_type, ToolType::AttemptCompletion)
{
// we break if it is any of these 2 events, since these
// require the user to intervene
println!("session_service::tool_use_agentic::reached_terminating_tool");
break;
}
}
Ok(AgentToolUseOutput::Cancelled) => {
// if it is cancelled then we should break
break;
}
Ok(AgentToolUseOutput::Failed(failed_to_parse_output)) => {
let human_message = format!(
r#"Your output was incorrect, please give me the output in the correct format:
{}"#,
failed_to_parse_output.to_owned()
);
human_message_ticker = human_message_ticker + 1;
session = session.human_message(
human_message_ticker.to_string(),
human_message,
UserContext::default(),
vec![],
repo_ref.clone(),
);
let _ = message_properties
.ui_sender()
.send(UIEventWithID::tool_not_found(
session_id.to_owned(),
tool_exchange_id.to_owned(),
"Failed to get tool output".to_owned(),
));
}
Err(e) => {
let _ = message_properties
.ui_sender()
.send(UIEventWithID::tool_not_found(
session_id.to_owned(),
tool_exchange_id.to_owned(),
e.to_string(),
));
Err(e)?
}
}
}
Ok(())
}

pub async fn code_edit_agentic(
&self,
session_id: String,
Expand Down
Loading

0 comments on commit 03e811b

Please sign in to comment.