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
68 changes: 51 additions & 17 deletions src/apps/desktop/src/api/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,22 @@ fn remote_workspace_from_info(info: &WorkspaceInfo) -> Option<crate::api::Remote
})
}

/// Resolves which SSH connection owns `path`. `request_preferred` comes from the workspace/session
/// (explicit scoping); legacy UI omits it and we fall back to the last single-remote pointer.
async fn lookup_remote_entry_for_path(
state: &State<'_, AppState>,
path: &str,
request_preferred: Option<&str>,
) -> Option<RemoteWorkspaceEntry> {
let hint = state
let manager = get_remote_workspace_manager()?;
let legacy = state
.get_remote_workspace_async()
.await
.map(|w| w.connection_id);
let manager = get_remote_workspace_manager()?;
manager.lookup_connection(path, hint.as_deref()).await
let preferred: Option<String> = request_preferred
.map(|s| s.to_string())
.or(legacy);
manager.lookup_connection(path, preferred.as_deref()).await
}

#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -142,6 +148,8 @@ pub struct ReadFileContentRequest {
#[serde(rename = "filePath")]
pub file_path: String,
pub encoding: Option<String>,
#[serde(default, rename = "remoteConnectionId")]
pub remote_connection_id: Option<String>,
}

#[derive(Debug, Deserialize)]
Expand All @@ -151,6 +159,8 @@ pub struct WriteFileContentRequest {
#[serde(rename = "filePath")]
pub file_path: String,
pub content: String,
#[serde(default, rename = "remoteConnectionId")]
pub remote_connection_id: Option<String>,
}

#[derive(Debug, Deserialize)]
Expand All @@ -173,11 +183,15 @@ pub struct GetFileMetadataRequest {
pub struct GetFileTreeRequest {
pub path: String,
pub max_depth: Option<usize>,
#[serde(default, rename = "remoteConnectionId")]
pub remote_connection_id: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct GetDirectoryChildrenRequest {
pub path: String,
#[serde(default, rename = "remoteConnectionId")]
pub remote_connection_id: Option<String>,
}

#[derive(Debug, Deserialize)]
Expand All @@ -186,6 +200,8 @@ pub struct GetDirectoryChildrenPaginatedRequest {
pub path: String,
pub offset: Option<usize>,
pub limit: Option<usize>,
#[serde(default)]
pub remote_connection_id: Option<String>,
}

#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -1366,8 +1382,12 @@ pub async fn get_file_tree(
}
}

let preferred = request.remote_connection_id.as_deref();
let filesystem_service = &state.filesystem_service;
match filesystem_service.build_file_tree(&request.path).await {
match filesystem_service
.build_file_tree_with_remote_hint(&request.path, preferred)
.await
{
Ok(nodes) => {
fn convert_node_to_json(
node: bitfun_core::infrastructure::FileTreeNode,
Expand Down Expand Up @@ -1433,9 +1453,10 @@ pub async fn get_directory_children(
}
}

let preferred = request.remote_connection_id.as_deref();
let filesystem_service = &state.filesystem_service;
match filesystem_service
.get_directory_contents(&request.path)
.get_directory_contents_with_remote_hint(&request.path, preferred)
.await
{
Ok(nodes) => {
Expand Down Expand Up @@ -1484,9 +1505,10 @@ pub async fn get_directory_children_paginated(
}
}

let preferred = request.remote_connection_id.as_deref();
let filesystem_service = &state.filesystem_service;
match filesystem_service
.get_directory_contents(&request.path)
.get_directory_contents_with_remote_hint(&request.path, preferred)
.await
{
Ok(nodes) => {
Expand Down Expand Up @@ -1527,7 +1549,13 @@ pub async fn read_file_content(
state: State<'_, AppState>,
request: ReadFileContentRequest,
) -> Result<String, String> {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.file_path).await {
if let Some(entry) = lookup_remote_entry_for_path(
&state,
&request.file_path,
request.remote_connection_id.as_deref(),
)
.await
{
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
let bytes = remote_fs.read_file(&entry.connection_id, &request.file_path).await
Expand All @@ -1553,7 +1581,13 @@ pub async fn write_file_content(
state: State<'_, AppState>,
request: WriteFileContentRequest,
) -> Result<(), String> {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.file_path).await {
if let Some(entry) = lookup_remote_entry_for_path(
&state,
&request.file_path,
request.remote_connection_id.as_deref(),
)
.await
{
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
remote_fs.write_file(&entry.connection_id, &request.file_path, request.content.as_bytes()).await
Expand Down Expand Up @@ -1618,7 +1652,7 @@ pub async fn check_path_exists(
state: State<'_, AppState>,
request: CheckPathExistsRequest,
) -> Result<bool, String> {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path, None).await {
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
return remote_fs.exists(&entry.connection_id, &request.path).await
Expand All @@ -1636,7 +1670,7 @@ pub async fn get_file_metadata(
) -> Result<serde_json::Value, String> {
use std::time::SystemTime;

if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path, None).await {
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;

Expand Down Expand Up @@ -1706,7 +1740,7 @@ pub async fn get_file_editor_sync_hash(
state: State<'_, AppState>,
request: GetFileMetadataRequest,
) -> Result<serde_json::Value, String> {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path, None).await {
let remote_fs = state
.get_remote_file_service_async()
.await
Expand Down Expand Up @@ -1742,7 +1776,7 @@ pub async fn rename_file(
state: State<'_, AppState>,
request: RenameFileRequest,
) -> Result<(), String> {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.old_path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.old_path, None).await {
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
remote_fs.rename(&entry.connection_id, &request.old_path, &request.new_path).await
Expand Down Expand Up @@ -1783,7 +1817,7 @@ pub async fn delete_file(
state: State<'_, AppState>,
request: DeleteFileRequest,
) -> Result<(), String> {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path, None).await {
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
remote_fs.remove_file(&entry.connection_id, &request.path).await
Expand All @@ -1807,7 +1841,7 @@ pub async fn delete_directory(
) -> Result<(), String> {
let recursive = request.recursive.unwrap_or(false);

if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path, None).await {
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
if recursive {
Expand All @@ -1834,7 +1868,7 @@ pub async fn create_file(
state: State<'_, AppState>,
request: CreateFileRequest,
) -> Result<(), String> {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path, None).await {
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
remote_fs.write_file(&entry.connection_id, &request.path, b"").await
Expand All @@ -1857,7 +1891,7 @@ pub async fn create_directory(
state: State<'_, AppState>,
request: CreateDirectoryRequest,
) -> Result<(), String> {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path, None).await {
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
remote_fs.create_dir_all(&entry.connection_id, &request.path).await
Expand Down Expand Up @@ -1887,7 +1921,7 @@ pub async fn list_directory_files(
) -> Result<Vec<String>, String> {
use std::path::Path;

if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path).await {
if let Some(entry) = lookup_remote_entry_for_path(&state, &request.path, None).await {
let remote_fs = state.get_remote_file_service_async().await
.map_err(|e| format!("Remote file service not available: {}", e))?;
let entries = remote_fs.read_dir(&entry.connection_id, &request.path).await
Expand Down
6 changes: 3 additions & 3 deletions src/apps/desktop/src/api/tool_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ pub async fn get_all_tools_info() -> Result<Vec<ToolInfo>, String> {
tool_infos.push(ToolInfo {
name: tool.name().to_string(),
description,
input_schema: tool.input_schema(),
input_schema: tool.input_schema_for_model().await,
is_readonly: tool.is_readonly(),
is_concurrency_safe: tool.is_concurrency_safe(None),
needs_permissions: tool.needs_permissions(None),
Expand All @@ -188,7 +188,7 @@ pub async fn get_readonly_tools_info() -> Result<Vec<ToolInfo>, String> {
tool_infos.push(ToolInfo {
name: tool.name().to_string(),
description,
input_schema: tool.input_schema(),
input_schema: tool.input_schema_for_model().await,
is_readonly: tool.is_readonly(),
is_concurrency_safe: tool.is_concurrency_safe(None),
needs_permissions: tool.needs_permissions(None),
Expand All @@ -212,7 +212,7 @@ pub async fn get_tool_info(tool_name: String) -> Result<Option<ToolInfo>, String
return Ok(Some(ToolInfo {
name: tool.name().to_string(),
description,
input_schema: tool.input_schema(),
input_schema: tool.input_schema_for_model().await,
is_readonly: tool.is_readonly(),
is_concurrency_safe: tool.is_concurrency_safe(None),
needs_permissions: tool.needs_permissions(None),
Expand Down
2 changes: 1 addition & 1 deletion src/crates/core/src/agentic/agents/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub use explore_agent::ExploreAgent;
pub use file_finder_agent::FileFinderAgent;
pub use generate_doc_agent::GenerateDocAgent;
pub use plan_mode::PlanMode;
pub use prompt_builder::{PromptBuilder, PromptBuilderContext};
pub use prompt_builder::{PromptBuilder, PromptBuilderContext, RemoteExecutionHints};
pub use registry::{
get_agent_registry, AgentCategory, AgentInfo, AgentRegistry, CustomSubagentConfig,
SubAgentSource,
Expand Down
2 changes: 1 addition & 1 deletion src/crates/core/src/agentic/agents/prompt_builder/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mod prompt_builder;

pub use prompt_builder::{PromptBuilder, PromptBuilderContext};
pub use prompt_builder::{PromptBuilder, PromptBuilderContext, RemoteExecutionHints};
Loading