Skip to content
Merged
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
26 changes: 19 additions & 7 deletions llm_client/src/clients/anthropic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ enum AnthropicMessageContent {
cache_control: Option<AnthropicCacheControl>,
},
#[serde(rename = "image")]
Image {
Image {
source: AnthropicImageSource,
cache_control: Option<AnthropicCacheControl>,
},
Expand Down Expand Up @@ -96,10 +96,22 @@ impl AnthropicMessageContent {

fn set_cache_control(&mut self, cache_control: Option<AnthropicCacheControl>) {
match self {
Self::Text { cache_control: ref mut cc, .. } => *cc = cache_control,
Self::Image { cache_control: ref mut cc, .. } => *cc = cache_control,
Self::ToolUse { cache_control: ref mut cc, .. } => *cc = cache_control,
Self::ToolReturn { cache_control: ref mut cc, .. } => *cc = cache_control,
Self::Text {
cache_control: ref mut cc,
..
} => *cc = cache_control,
Self::Image {
cache_control: ref mut cc,
..
} => *cc = cache_control,
Self::ToolUse {
cache_control: ref mut cc,
..
} => *cc = cache_control,
Self::ToolReturn {
cache_control: ref mut cc,
..
} => *cc = cache_control,
}
}
}
Expand Down Expand Up @@ -275,7 +287,7 @@ impl AnthropicRequest {
let mut content = Vec::new();
let mut anthropic_message_content =
AnthropicMessageContent::text(message.content().to_owned(), None);

let images = message
.images()
.into_iter()
Expand Down Expand Up @@ -924,4 +936,4 @@ impl LLMClient for AnthropicClient {

Ok(buffered_string)
}
}
}
6 changes: 3 additions & 3 deletions sidecar/src/agentic/tool/session/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1143,15 +1143,15 @@ impl SessionService {
storage_path: String,
) -> Result<SearchTreeMinimal, SymbolError> {
let session = self.load_from_storage(storage_path).await?;

// Create a SearchTreeMinimal from the action nodes
let search_tree = SearchTreeMinimal::from_action_nodes(
session.action_nodes(),
session.repo_ref().name.to_owned(),
"".to_owned(), // No need for MCTS log directory
"".to_owned(), // No need for MCTS log directory
);

Ok(search_tree)
}

Expand Down Expand Up @@ -1366,4 +1366,4 @@ pub enum TestGenerateCompletion {
LLMChoseToFinish(String),
/// Hit the maximum iteration limit (lower confidence)
HitIterationLimit(String),
}
}
10 changes: 9 additions & 1 deletion sidecar/src/agentic/tool/session/tool_use_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
message_properties.ui_sender().clone(),
message_properties.request_id_str(),
vec![system_message, user_message],
Some("context_crunching".to_owned()),
)
.await?
{
Expand Down Expand Up @@ -1393,6 +1394,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
ui_sender.clone(),
exchange_id,
final_messages.to_vec(),
None,
)
.await
{
Expand Down Expand Up @@ -1420,6 +1422,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
ui_sender.clone(),
exchange_id,
final_messages.to_vec(),
None,
)
.await?
{
Expand Down Expand Up @@ -1448,6 +1451,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
ui_sender,
exchange_id,
final_messages,
None,
)
.await?
{
Expand All @@ -1466,6 +1470,7 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
ui_sender: tokio::sync::mpsc::UnboundedSender<UIEventWithID>,
exchange_id: &str,
final_messages: Vec<LLMClientMessage>,
event_type: Option<String>,
) -> Result<Option<ToolUseAgentOutput>, SymbolError> {
let agent_temperature = self.temperature;
let (sender, receiver) =
Expand All @@ -1488,7 +1493,10 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
),
llm_properties.provider().clone(),
vec![
("event_type".to_owned(), "tool_use".to_owned()),
(
"event_type".to_owned(),
event_type.unwrap_or_else(|| "tool_use".to_owned()),
),
("root_id".to_owned(), cloned_root_request_id),
]
.into_iter()
Expand Down
2 changes: 1 addition & 1 deletion sidecar/src/mcts/action_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2165,4 +2165,4 @@ where
map_serializer.serialize_entry(&k.to_string(), v)?;
}
map_serializer.end()
}
}
90 changes: 55 additions & 35 deletions sidecar/src/webserver/agentic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -846,76 +846,96 @@ impl ApiResponse for MCTSDataResponse {}

pub async fn get_mcts_data(
Extension(app): Extension<Application>,
Json(MCTSDataRequest { session_id, exchange_id }): Json<MCTSDataRequest>,
Json(MCTSDataRequest {
session_id,
exchange_id,
}): Json<MCTSDataRequest>,
) -> Result<impl IntoResponse> {
let session_storage_path = check_session_storage_path(app.config.clone(), session_id.to_string()).await;
let session_storage_path =
check_session_storage_path(app.config.clone(), session_id.to_string()).await;
let session_service = app.session_service.clone();

// Get the MCTS data from session storage
let mcts_data = session_service.get_mcts_data(&session_id, &exchange_id, session_storage_path).await;

let mcts_data = session_service
.get_mcts_data(&session_id, &exchange_id, session_storage_path)
.await;

// Generate HTML with color-coded tool types and tool input/output
let html = match mcts_data {
Ok(data) => {
let mut html = String::from(r#"<html><head><style>
let mut html = String::from(
r#"<html><head><style>
.tool-type { display: inline-block; padding: 4px 8px; margin: 2px; border-radius: 4px; color: white; }
.tool-content { margin: 8px 0; padding: 8px; background: #f5f5f5; border-radius: 4px; }
pre { margin: 0; white-space: pre-wrap; }
.node { margin: 8px 0; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
</style></head><body>"#);

</style></head><body>"#,
);

html.push_str("<div class='mcts-tree'>");

// Add nodes in order
for node in data.nodes() {
if let Some(action) = &node.action() {
let tool_type = action.to_tool_type();
if let Some(tool_type) = tool_type {
// Get color based on tool type using the same logic as print_tree
let color = match tool_type {
ToolType::CodeEditing => "#4A90E2", // blue
ToolType::FindFiles => "#F5A623", // yellow
ToolType::ListFiles => "#F5A623", // yellow
ToolType::CodeEditing => "#4A90E2", // blue
ToolType::FindFiles => "#F5A623", // yellow
ToolType::ListFiles => "#F5A623", // yellow
ToolType::SearchFileContentWithRegex => "#9013FE", // purple
ToolType::OpenFile => "#E91E63", // magenta
ToolType::SemanticSearch => "#9013FE", // purple
ToolType::LSPDiagnostics => "#00BCD4", // cyan
ToolType::TerminalCommand => "#FF5252", // red
ToolType::AskFollowupQuestions => "#757575", // gray
ToolType::AttemptCompletion => "#4CAF50", // green
ToolType::RepoMapGeneration => "#E91E63", // magenta
ToolType::TestRunner => "#FF5252", // red
ToolType::Reasoning => "#4A90E2", // blue
ToolType::ContextCrunching => "#4A90E2", // blue
ToolType::RequestScreenshot => "#757575", // gray
ToolType::McpTool(_) => "#00BCD4", // cyan
_ => "#9E9E9E", // default gray for other variants
ToolType::OpenFile => "#E91E63", // magenta
ToolType::SemanticSearch => "#9013FE", // purple
ToolType::LSPDiagnostics => "#00BCD4", // cyan
ToolType::TerminalCommand => "#FF5252", // red
ToolType::AskFollowupQuestions => "#757575", // gray
ToolType::AttemptCompletion => "#4CAF50", // green
ToolType::RepoMapGeneration => "#E91E63", // magenta
ToolType::TestRunner => "#FF5252", // red
ToolType::Reasoning => "#4A90E2", // blue
ToolType::ContextCrunching => "#4A90E2", // blue
ToolType::RequestScreenshot => "#757575", // gray
ToolType::McpTool(_) => "#00BCD4", // cyan
_ => "#9E9E9E", // default gray for other variants
};

html.push_str(&format!("<div class='node'>\n"));
html.push_str(&format!("<div class='tool-type' style='background: {}'>{:?}</div>\n", color, tool_type));

html.push_str(&format!(
"<div class='tool-type' style='background: {}'>{:?}</div>\n",
color, tool_type
));

// Add tool input/output with proper formatting
html.push_str("<div class='tool-content'>\n");
html.push_str(&format!("<h4>Tool Input:</h4>\n<pre>{}</pre>\n", action.to_string()));
html.push_str(&format!(
"<h4>Tool Input:</h4>\n<pre>{}</pre>\n",
action.to_string()
));
if let Some(observation) = node.observation() {
html.push_str(&format!("<h4>Tool Output:</h4>\n<pre>{}</pre>\n", observation.message()));
html.push_str(&format!(
"<h4>Tool Output:</h4>\n<pre>{}</pre>\n",
observation.message()
));
}
html.push_str("</div>\n"); // Close tool-content

// Add reward if present
if let Some(reward) = node.reward() {
html.push_str(&format!("<div class='reward'>Reward: {}</div>\n", reward.value()));
html.push_str(&format!(
"<div class='reward'>Reward: {}</div>\n",
reward.value()
));
}

html.push_str("</div>\n"); // Close node
}
}
}

html.push_str("</div></body></html>");
html
},
}
Err(_) => String::from("<html><body>No MCTS data found</body></html>"),
};

Expand Down Expand Up @@ -2123,4 +2143,4 @@ pub async fn agent_session_plan(
let stream = init_stream.chain(answer_stream).chain(done_stream);

Ok(Sse::new(Box::pin(stream)))
}
}