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
13 changes: 0 additions & 13 deletions crates/flock-agent/src/graph/nodes/llm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,6 @@ pub fn make_llm_node(
let local_estimate = estimate::estimate_tokens_from_messages(&msgs_for_estimate, Some(&system));
let effective_watermark = if turn_input_tokens > 0 { turn_input_tokens } else { local_estimate };

if local_estimate > turn_input_tokens && turn_input_tokens > 0
&& local_estimate.saturating_sub(turn_input_tokens) > 10_000
{
ctx.output.emit_info(&format!(
"Token watermark override: provider={}, local_estimate={}, using={}",
turn_input_tokens, local_estimate, effective_watermark
));
}

let mut assistant_content: Vec<ContentBlock> = Vec::new();
if !thinking_text.is_empty() {
assistant_content.push(ContentBlock::Thinking { thinking: thinking_text });
Expand All @@ -176,10 +167,6 @@ pub fn make_llm_node(
state.total_output_tokens
};

ctx.output.emit_info(&format!(
"[node] <<< exiting llm (tool_calls={})",
tool_calls.len()
));

Ok(json!({
"messages": [assistant_json],
Expand Down
36 changes: 27 additions & 9 deletions crates/flock-core/src/config/settings/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,23 @@ impl Config {

// Check active_model (set by UI) to override default provider/model
let active_model: Option<serde_json::Value> = db.get_config("active_model").await;
let (active_provider, active_model_name) = if let Some(am) = active_model {
let (mut active_provider, active_model_name) = if let Some(am) = active_model {
let p = am.get("provider_id").and_then(|v| v.as_str()).map(|s| s.to_string());
let m = am.get("model_name").and_then(|v| v.as_str()).map(|s| s.to_string());
(p, m)
} else {
(None, None)
};

// If default model is not set, try to find the first authenticated provider
if active_provider.is_none() && (default_cfg.model.is_none() || default_cfg.model.as_ref().map(|s| s.is_empty()).unwrap_or(true)) {
if let Ok(providers) = db.list_providers().await {
if let Some(first_auth_prov) = providers.iter().find(|p| p.is_available) {
active_provider = Some(first_auth_prov.id.clone());
}
}
}

// Determine provider: CLI > active_model > default
let provider_str = cli.provider.as_deref()
.or(active_provider.as_deref())
Expand Down Expand Up @@ -197,18 +206,27 @@ impl Config {
});

// Determine model: CLI > active_model > provider config > default
let model = cli
let mut model_opt = cli
.model
.clone()
.or(active_model_name.clone())
.or(provider_config.model.clone())
.or(default_cfg.model.clone())
.unwrap_or_else(|| match provider {
ProviderType::Anthropic => "claude-sonnet-4-20250514".into(),
ProviderType::OpenAI => "gpt-4o".into(),
ProviderType::Bedrock => "anthropic.claude-sonnet-4-20250514-v1:0".into(),
ProviderType::Vertex => "claude-sonnet-4@20250514".into(),
});
.or(default_cfg.model.clone());

if model_opt.is_none() {
if let Ok(models) = db.list_models(&provider_label).await {
if let Some(first_online_model) = models.iter().find(|m| m.is_online) {
model_opt = Some(first_online_model.model_name.clone());
}
}
}

let model = model_opt.unwrap_or_else(|| match provider {
ProviderType::Anthropic => "claude-sonnet-4-20250514".into(),
ProviderType::OpenAI => "gpt-4o".into(),
ProviderType::Bedrock => "anthropic.claude-sonnet-4-20250514-v1:0".into(),
ProviderType::Vertex => "claude-sonnet-4@20250514".into(),
});

let max_tokens = cli.max_tokens.unwrap_or(default_cfg.max_tokens);
let max_turns = cli.max_turns.or(default_cfg.max_turns);
Expand Down
16 changes: 2 additions & 14 deletions crates/flock-tools/src/daytona/lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,14 @@ pub async fn destroy_active_sandbox(db: &DbManager) -> anyhow::Result<()> {
}
}

crate::emit_info(&flock_core::tr(&format!("正在销毁 Daytona 沙盒 {}...", sandbox_id), &format!("Destroying Daytona sandbox {}...", sandbox_id)));
let del_url = format!("{}/api/sandbox/{}", base, sandbox_id);
match client.delete(&del_url)
.header("Authorization", format!("Bearer {}", api_key))
.send()
.await
{
Ok(resp) => {
if resp.status().is_success() {
crate::emit_info(&flock_core::tr(&format!("Daytona 沙盒 {} 已销毁。", sandbox_id), &format!("Daytona sandbox {} has been destroyed.", sandbox_id)));
} else {
if !resp.status().is_success() {
let status = resp.status();
let body = resp.text().await.unwrap_or_default();
crate::emit_info(&flock_core::tr(&format!("销毁沙盒返回非成功状态 (HTTP {}): {}", status, body), &format!("Destroying sandbox returned non-success status (HTTP {}): {}", status, body)));
Expand Down Expand Up @@ -108,10 +105,6 @@ pub async fn get_or_create_active_sandbox(db: &DbManager) -> anyhow::Result<Stri
"mountPath": mount_path
}
]);
crate::emit_info(&flock_core::tr(
&format!("Volume {} 将挂载到 {}", vid, mount_path),
&format!("Volume {} will be mounted to {}", vid, mount_path)
));
}

let create_url = format!("{}/api/sandbox", base);
Expand Down Expand Up @@ -246,12 +239,7 @@ pub async fn get_or_create_active_sandbox(db: &DbManager) -> anyhow::Result<Stri
let ensure_workspace_cmd = "mkdir -p /workspace && ls -la /workspace";
match crate::daytona::execute_command_in_sandbox(db, &sandbox_id, ensure_workspace_cmd).await {
Ok((out, code)) => {
if code == 0 {
crate::emit_info(&flock_core::tr(
&format!("/workspace 目录已就绪: {}", out),
&format!("/workspace directory is ready: {}", out)
));
} else {
if code != 0 {
crate::emit_info(&flock_core::tr(
&format!("创建 /workspace 目录失败 (退出码 {}): {}", code, out),
&format!("Failed to create /workspace directory (exit code {}): {}", code, out)
Expand Down
8 changes: 1 addition & 7 deletions crates/flock-tools/src/daytona/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ fn should_ignore(path: &Path) -> bool {
}

pub async fn sync_up(db: &DbManager, sandbox_id: &str, local_workspace: &Path) -> anyhow::Result<()> {
crate::emit_info("正在将本地工作区同步到沙盒 (Sync Up)...");

// Create a temporary tarball
let tar_path = std::env::temp_dir().join(format!("flock_sync_up_{}.tar.gz", sandbox_id));
let tar_file = fs::File::create(&tar_path).context("Failed to create tar file")?;
Expand All @@ -32,7 +30,7 @@ pub async fn sync_up(db: &DbManager, sandbox_id: &str, local_workspace: &Path) -
if path.is_file() {
if let Ok(rel_path) = path.strip_prefix(local_workspace) {
if let Err(e) = tar.append_path_with_name(path, rel_path) {
crate::emit_info(&format!("Failed to tar {}: {}", rel_path.display(), e));
log::warn!("Failed to tar {}: {}", rel_path.display(), e);
}
}
}
Expand All @@ -50,13 +48,10 @@ pub async fn sync_up(db: &DbManager, sandbox_id: &str, local_workspace: &Path) -
execute_command_in_sandbox(db, sandbox_id, cmd).await?;

let _ = fs::remove_file(tar_path);
crate::emit_info("同步到沙盒完成。");
Ok(())
}

pub async fn sync_down(db: &DbManager, sandbox_id: &str, local_workspace: &Path) -> anyhow::Result<()> {
crate::emit_info("正在将沙盒文件同步回本地 (Sync Down)...");

// Create a tarball in sandbox
let cmd = "cd /workspace && tar -czf .flock_sync_down.tar.gz --exclude='.flock_sync_down.tar.gz' --exclude='.git' --exclude='node_modules' --exclude='target' .";
execute_command_in_sandbox(db, sandbox_id, cmd).await?;
Expand Down Expand Up @@ -136,6 +131,5 @@ pub async fn sync_down(db: &DbManager, sandbox_id: &str, local_workspace: &Path)
let cmd = "rm -f /workspace/.flock_sync_down.tar.gz";
let _ = execute_command_in_sandbox(db, sandbox_id, cmd).await;

crate::emit_info("同步回本地完成。");
Ok(())
}
10 changes: 0 additions & 10 deletions crates/flock-tools/src/tools/sandbox/browser/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,6 @@ pub async fn handle_interactive(
);
let _ = execute_command_in_sandbox(db, sandbox_id, &check_and_start_cmd).await;

// Run security check script and auto-navigate
crate::emit_info(&flock_core::tr(
&format!("正在远程浏览器中打开网页并分析安全要素: {}...", url),
&format!("Opening web page in remote browser and analyzing security elements: {}...", url),
));

let (need_takeover, has_password, has_captcha, screenshot_saved) =
run_security_check(db, sandbox_id, session_id, name_id, url).await?;

Expand All @@ -97,10 +91,6 @@ pub async fn handle_interactive(
};

if !need_takeover {
crate::emit_info(&flock_core::tr(
"网页分析完毕:未检测到输入密码、验证码等敏感校验元素。自动跳过人机接管。",
"Page analysis complete: No sensitive verification elements (password inputs, captchas) detected. Skipping human takeover automatically.",
));
return Ok(format!(
"人机协同远程桌面已拉起!网页分析完成:未检测到输入密码 (has_password: {})、验证码 (has_captcha: {}) 等敏感验证元素。**为了提高大模型执行效率,已自动跳过人工接管,Agent 继续流式自动运转。**{}\n\n[Remote VNC Link]({})",
has_password, has_captcha, image_md, proxy_url
Expand Down
5 changes: 0 additions & 5 deletions crates/flock-tools/src/tools/sandbox/browser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,6 @@ async fn execute_regular_action(
display = DISPLAY_ID
);

let display_url = url.as_deref().unwrap_or("当前页面");
crate::emit_info(&flock_core::tr(
&format!("正在沙盒中执行网页操作并渲染: {}...", display_url),
&format!("Executing page actions and rendering in sandbox: {}...", display_url),
));
let (stdout_stderr, exit_code) = execute_command_in_sandbox(db, sandbox_id, &run_cmd)
.await
.map_err(|e| format!("浏览器工具执行出错: {}", e))?;
Expand Down
1 change: 0 additions & 1 deletion crates/flock-tools/src/tools/sandbox/code_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ pub async fn code_execution(code: String) -> Result<String, String> {
b64_code
);

crate::emit_info(&flock_core::tr("正在沙盒中执行代码...", "Executing code in sandbox..."));
let (stdout_stderr, exit_code) = execute_command_in_sandbox(&db, &sandbox_id, &setup_and_run_cmd).await
.map_err(|e| format!("代码执行失败: {}", e))?;

Expand Down
10 changes: 0 additions & 10 deletions crates/flock-tools/src/tools/sandbox/computer_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ async fn capture_desktop_screenshot(
);

let abs_path_str = ss_path.to_string_lossy().to_string();
crate::emit_info(&flock_core::tr(
"远程桌面最新状态已成功截取并拉回工作区预览!",
"Latest remote desktop screenshot captured and synced to workspace!",
));
return (format!("\n\n![桌面截图](file:///{})", abs_path_str), true);
}
}
Expand Down Expand Up @@ -153,10 +149,6 @@ pub async fn computer_use(
// --- exec action: 直接在沙盒内执行 shell 命令,无需启动 VNC 桌面 ---
if act == "exec" {
let cmd = command.ok_or_else(|| "`exec` action 需要提供 `command` 参数。例如:command=\"mkdir /workspace/my_project\"".to_string())?;
crate::emit_info(&flock_core::tr(
&format!("正在沙盒中执行命令: {}...", cmd),
&format!("Executing command in sandbox: {}...", cmd)
));
let (output, exit_code) = execute_command_in_sandbox(&db, &sandbox_id, &cmd).await
.map_err(|e| format!("沙盒命令执行失败: {}", e))?;

Expand Down Expand Up @@ -307,8 +299,6 @@ pub async fn computer_use(
}
}

// 4. Capture desktop screenshot after action
crate::emit_info(&flock_core::tr("正在捕获当前远程桌面截图并渲染预览...", "Capturing current remote desktop screenshot for preview..."));
let (image_md, _screenshot_saved) = capture_desktop_screenshot(&db, &sandbox_id, &session_id, &name_id).await;

let proxy_url = match crate::daytona::get_sandbox_vnc_url(&db, &sandbox_id).await {
Expand Down
23 changes: 4 additions & 19 deletions crates/flock-tools/src/tools/sandbox/fs_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ use langgraph::tool;
#[tool("SandboxRead")]
pub async fn sandbox_read(path: String) -> Result<String, String> {
let db = crate::get_db_manager().ok_or_else(|| "Database manager not initialized".to_string())?;
crate::emit_info(&flock_core::tr(&format!("正在沙盒中读取文件: {}...", path), &format!("Reading file in sandbox: {}...", path)));
DaytonaFs::read_file(&db, &path).await.map_err(|e| format!("读取失败: {}", e))
}

Expand All @@ -50,8 +49,6 @@ pub async fn sandbox_read(path: String) -> Result<String, String> {
#[tool("SandboxWrite")]
pub async fn sandbox_write(path: String, content: String) -> Result<String, String> {
let db = crate::get_db_manager().ok_or_else(|| "Database manager not initialized".to_string())?;
crate::emit_info(&flock_core::tr(&format!("正在沙盒中写入文件: {}...", path), &format!("Writing file in sandbox: {}...", path)));

// Write to cloud sandbox
DaytonaFs::write_file(&db, &path, &content).await.map_err(|e| format!("写入失败: {}", e))?;

Expand All @@ -69,13 +66,8 @@ pub async fn sandbox_write(path: String, content: String) -> Result<String, Stri
}

// Write file to local workspace
match std::fs::write(&local_path, &content) {
Ok(_) => {
crate::emit_info(&flock_core::tr(&format!("文件已同步到本地: {}", local_path.display()), &format!("File synced to local: {}", local_path.display())));
}
Err(e) => {
crate::emit_info(&flock_core::tr(&format!("同步到本地失败: {} (文件仍在云端沙盒中)", e), &format!("Sync to local failed: {} (File remains in sandbox)", e)));
}
if let Err(e) = std::fs::write(&local_path, &content) {
crate::emit_info(&flock_core::tr(&format!("同步到本地失败: {} (文件仍在云端沙盒中)", e), &format!("Sync to local failed: {} (File remains in sandbox)", e)));
}
}

Expand Down Expand Up @@ -104,8 +96,6 @@ pub async fn sandbox_write(path: String, content: String) -> Result<String, Stri
#[tool("SandboxEdit")]
pub async fn sandbox_edit(path: String, old_text: String, new_text: String) -> Result<String, String> {
let db = crate::get_db_manager().ok_or_else(|| "Database manager not initialized".to_string())?;
crate::emit_info(&flock_core::tr(&format!("正在沙盒中编辑文件: {}...", path), &format!("Editing file in sandbox: {}...", path)));

let content = DaytonaFs::read_file(&db, &path).await.map_err(|e| format!("读取失败: {}", e))?;
if !content.contains(&old_text) {
return Err("The old_text was not found in the file.".to_string());
Expand All @@ -128,13 +118,8 @@ pub async fn sandbox_edit(path: String, old_text: String, new_text: String) -> R
}

// Write file to local workspace
match std::fs::write(&local_path, &new_content) {
Ok(_) => {
crate::emit_info(&flock_core::tr(&format!("文件已同步到本地: {}", local_path.display()), &format!("File synced to local: {}", local_path.display())));
}
Err(e) => {
crate::emit_info(&flock_core::tr(&format!("同步到本地失败: {} (文件仍在云端沙盒中)", e), &format!("Sync to local failed: {} (File remains in sandbox)", e)));
}
if let Err(e) = std::fs::write(&local_path, &new_content) {
crate::emit_info(&flock_core::tr(&format!("同步到本地失败: {} (文件仍在云端沙盒中)", e), &format!("Sync to local failed: {} (File remains in sandbox)", e)));
}
}

Expand Down
4 changes: 0 additions & 4 deletions crates/flock-tools/src/tools/sandbox/sandbox_exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ pub async fn sandbox_exec(
final_cmd
};

crate::emit_info(&flock_core::tr(
&format!("正在沙盒中执行命令: {}...", command),
&format!("Executing command in sandbox: {}...", command)
));
let (output, exit_code) = execute_command_in_sandbox(&db, &sandbox_id, &cmd_with_timeout).await
.map_err(|e| format!("沙盒命令执行失败: {}", e))?;

Expand Down
Loading
Loading