feat: persist sgclaw browser conversations

This commit is contained in:
zyl
2026-03-27 01:57:42 +08:00
parent bae0e452a5
commit d315c13f66
11 changed files with 402 additions and 20 deletions

View File

@@ -4,8 +4,11 @@ pub mod runtime;
use std::ffi::OsString;
use std::path::PathBuf;
use crate::compat::runtime::CompatTaskContext;
use crate::config::DeepSeekSettings;
use crate::pipe::{AgentMessage, BrowserMessage, BrowserPipeTool, PipeError, Transport};
use crate::pipe::{
AgentMessage, BrowserMessage, BrowserPipeTool, ConversationMessage, PipeError, Transport,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AgentRuntimeContext {
@@ -85,6 +88,41 @@ fn send_mode_log<T: Transport>(transport: &T, mode: &str) -> Result<(), PipeErro
})
}
fn explicit_non_task_response(history: &[ConversationMessage], instruction: &str) -> Option<String> {
if !history.is_empty() {
return None;
}
let trimmed = instruction.trim();
if trimmed.is_empty() {
return Some("sgClaw 目前只处理浏览器任务,请直接描述要打开、搜索、点击或提取的网页操作。".to_string());
}
const TASK_HINTS: &[&str] = &[
"打开", "搜索", "点击", "输入", "导航", "跳转", "访问", "提取", "获取", "网页", "页面",
"标签页", "百度", "知乎", "google", "open", "search", "click", "type", "navigate",
];
if TASK_HINTS.iter().any(|hint| trimmed.contains(hint)) {
return None;
}
const CHITCHAT_INPUTS: &[&str] = &[
"hi", "hello", "hey", "你好", "您好", "", "在吗", "你是谁", "介绍一下你自己",
];
if CHITCHAT_INPUTS
.iter()
.any(|candidate| trimmed.eq_ignore_ascii_case(candidate) || trimmed == *candidate)
{
return Some("sgClaw 现在是浏览器任务入口,不做通用闲聊。请直接说你想在网页上执行什么操作,例如“打开百度搜索天气”。".to_string());
}
if trimmed.chars().count() <= 8 {
return Some("sgClaw 现在只处理浏览器任务。请直接描述网页操作目标,例如“打开知乎搜索天气”或“提取当前页面标题”。".to_string());
}
None
}
fn execute_plan<T: Transport>(
transport: &T,
browser_tool: &BrowserPipeTool<T>,
@@ -142,7 +180,36 @@ pub fn handle_browser_message_with_context<T: Transport + 'static>(
message: BrowserMessage,
) -> Result<(), PipeError> {
match message {
BrowserMessage::SubmitTask { instruction } => {
BrowserMessage::SubmitTask {
instruction,
conversation_id,
messages,
page_url,
page_title,
} => {
if let Some(summary) = explicit_non_task_response(&messages, &instruction) {
return transport.send(&AgentMessage::TaskComplete {
success: false,
summary,
});
}
let task_context = CompatTaskContext {
conversation_id: (!conversation_id.trim().is_empty())
.then_some(conversation_id.clone()),
messages,
page_url: (!page_url.trim().is_empty()).then_some(page_url),
page_title: (!page_title.trim().is_empty()).then_some(page_title),
};
if !task_context.messages.is_empty() {
let _ = transport.send(&AgentMessage::LogEntry {
level: "info".to_string(),
message: format!(
"continuing conversation with {} prior turns",
task_context.messages.len()
),
});
}
let completion = match context.load_deepseek_settings() {
Ok(Some(settings)) => {
let _ = transport.send(&AgentMessage::LogEntry {
@@ -159,6 +226,7 @@ pub fn handle_browser_message_with_context<T: Transport + 'static>(
transport,
browser_tool.clone(),
&instruction,
&task_context,
&context.workspace_root,
&settings,
) {