优化OpenClaw会话解析

This commit is contained in:
xintaofei
2026-03-17 15:35:34 +08:00
parent 2240f3054d
commit f517f4fcbb
4 changed files with 739 additions and 287 deletions

View File

@@ -156,6 +156,15 @@ async fn build_agent(
parts.push("--session".into());
parts.push(key.clone());
}
// When creating a new conversation (no session_id to resume),
// pass --reset-session so OpenClaw mints a fresh transcript
// instead of appending to the previous one.
if runtime_env
.get("OPENCLAW_RESET_SESSION")
.map_or(false, |v| v == "1")
{
parts.push("--reset-session".into());
}
}
let refs: Vec<&str> = parts.iter().map(|s| s.as_str()).collect();
AcpAgent::from_args(&refs).map_err(|e| AcpError::SpawnFailed(e.to_string()))

View File

@@ -1306,9 +1306,15 @@ pub async fn acp_connect(
)));
}
let local_config_json = load_agent_local_config_json(agent_type);
let runtime_env =
let mut runtime_env =
build_runtime_env_from_setting(agent_type, setting.as_ref(), local_config_json.as_deref());
// For OpenClaw: when creating a new conversation (no session_id to resume),
// signal that we want a fresh transcript via --reset-session.
if agent_type == AgentType::OpenClaw && session_id.is_none() {
runtime_env.insert("OPENCLAW_RESET_SESSION".into(), "1".into());
}
if let registry::AgentDistribution::Npx { package, .. } = meta.distribution {
if detect_npx_cached_version(package).await.is_none() {
prepare_npx_package(package).await?;

View File

@@ -261,9 +261,18 @@ pub async fn get_folder_conversation(
.await
.map_err(AppCommandError::from)?;
let (turns, session_stats) = if let Some(ref ext_id) = summary.external_id {
let (turns, session_stats, resolved_ext_id) = if let Some(ref ext_id) = summary.external_id
{
let at = summary.agent_type;
let eid = ext_id.clone();
let db_created_at = summary.created_at;
let folder_path_for_fallback = {
let folder = folder_service::get_folder_by_id(&db.conn, summary.folder_id)
.await
.ok()
.flatten();
folder.map(|f| f.path)
};
tokio::task::spawn_blocking(move || -> Result<_, AppCommandError> {
let parser: Box<dyn AgentParser> = match at {
AgentType::ClaudeCode => Box::new(ClaudeParser::new()),
@@ -271,13 +280,47 @@ pub async fn get_folder_conversation(
AgentType::OpenCode => Box::new(OpenCodeParser::new()),
AgentType::Gemini => Box::new(GeminiParser::new()),
AgentType::OpenClaw => Box::new(OpenClawParser::new()),
_ => return Ok((vec![], None)),
_ => return Ok((vec![], None, None)),
};
// If the external session file doesn't exist yet (e.g., new ACP session
// not yet synced to disk), return empty turns instead of failing.
match parser.get_conversation(&eid) {
Ok(d) => Ok((d.turns, d.session_stats)),
Err(crate::parsers::ParseError::ConversationNotFound(_)) => Ok((vec![], None)),
Ok(d) => Ok((d.turns, d.session_stats, None)),
Err(crate::parsers::ParseError::ConversationNotFound(_)) => {
// For OpenClaw, the external_id may be an ACP session UUID that
// doesn't correspond to any JSONL file. Fall back to matching
// by title and folder_path from the parsed conversation list.
if at == AgentType::OpenClaw {
if let Ok(all) = parser.list_conversations() {
// Filter by folder_path first, then find the closest
// started_at match within 300 seconds of db_created_at.
let matched = all
.into_iter()
.filter(|c| {
c.folder_path
.as_ref()
.zip(folder_path_for_fallback.as_ref())
.is_some_and(|(a, b)| path_eq_for_matching(a, b))
})
.min_by_key(|c| {
(c.started_at - db_created_at).num_seconds().unsigned_abs()
})
.filter(|c| {
let diff = (c.started_at - db_created_at).num_seconds().unsigned_abs();
diff < 300
});
if let Some(conv) = matched {
let new_ext_id = conv.id.clone();
if let Ok(d) = parser.get_conversation(&new_ext_id) {
return Ok((
d.turns,
d.session_stats,
Some(new_ext_id),
));
}
}
}
}
Ok((vec![], None, None))
}
Err(e) => Err(parse_error_to_app_error(e)),
}
})
@@ -289,9 +332,16 @@ pub async fn get_folder_conversation(
.with_detail(e.to_string())
})??
} else {
(vec![], None)
(vec![], None, None)
};
// If we resolved a different external_id (e.g. ACP UUID → parser branch ID),
// update the database so future lookups are direct.
if let Some(new_ext_id) = resolved_ext_id {
let _ =
conversation_service::update_external_id(&db.conn, conversation_id, new_ext_id).await;
}
let mut summary = summary;
summary.message_count = turns.len() as u32;

File diff suppressed because it is too large Load Diff