fix(session): 修复session log模式下子Agent token统计遗漏 (#2821)

* fix(session): 修复session log模式下子Agent token统计遗漏

collect_jsonl_files() 只扫描了两层目录,遗漏了子Agent的JSONL日志文件,
导致子Agent的独立token使用数据完全未统计到session费用中。
(仅影响session log模式,proxy代理模式不受影响)

* refactor(session): optimize collect_jsonl_files logic

- Replace two independent if statements with if-else for mutually exclusive conditions
- Remove unnecessary clone() when pushing file paths
- Add clarifying comments for main session vs subagent files
- Apply cargo fmt for consistent formatting

Performance improvement: Eliminates redundant clone() operations when
processing .jsonl files, as a path cannot be both a file and a directory.

---------

Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
LaoYueHanNi
2026-05-18 10:00:57 +08:00
committed by GitHub
Unverified
parent ed33990b9c
commit bbce75fcda
+43 -1
View File
@@ -107,7 +107,11 @@ pub fn sync_claude_session_logs(db: &Database) -> Result<SessionSyncResult, AppE
Ok(result)
}
/// 收集目录下所有 .jsonl 文件
/// 收集目录下所有 .jsonl 文件(含子 agent 文件)
///
/// 扫描三层固定深度,不使用递归,避免死循环:
/// projects_dir/项目目录/*.jsonl (主会话)
/// projects_dir/项目目录/SESSION_ID/subagents/*.jsonl (子 agent)
fn collect_jsonl_files(projects_dir: &Path) -> Vec<PathBuf> {
let mut files = Vec::new();
@@ -126,7 +130,22 @@ fn collect_jsonl_files(projects_dir: &Path) -> Vec<PathBuf> {
for sub_entry in sub_entries.flatten() {
let sub_path = sub_entry.path();
if sub_path.extension().and_then(|e| e.to_str()) == Some("jsonl") {
// 主会话 JSONL 文件
files.push(sub_path);
} else if sub_path.is_dir() {
// 扫描子 agent 目录: 项目/SESSION_ID/subagents/*.jsonl
let subagents_dir = sub_path.join("subagents");
if subagents_dir.is_dir() {
if let Ok(agent_entries) = fs::read_dir(&subagents_dir) {
for agent_entry in agent_entries.flatten() {
let agent_path = agent_entry.path();
if agent_path.extension().and_then(|e| e.to_str()) == Some("jsonl")
{
files.push(agent_path);
}
}
}
}
}
}
}
@@ -637,4 +656,27 @@ mod tests {
Ok(())
}
#[test]
fn test_collect_jsonl_files_includes_subagents() {
let tmp = std::env::temp_dir().join(format!("cc-switch-test-{}", uuid::Uuid::new_v4()));
let project = tmp.join("project");
let session_dir = project.join("test-session");
let subagents_dir = session_dir.join("subagents");
fs::create_dir_all(&subagents_dir).unwrap();
fs::write(project.join("main.jsonl"), "{}").unwrap();
fs::write(subagents_dir.join("agent-abc.jsonl"), "{}").unwrap();
let files = collect_jsonl_files(&tmp);
assert_eq!(files.len(), 2);
let paths: Vec<String> = files
.iter()
.map(|p| p.to_string_lossy().to_string())
.collect();
assert!(paths.iter().any(|p| p.contains("main.jsonl")));
assert!(paths.iter().any(|p| p.contains("agent-abc.jsonl")));
fs::remove_dir_all(&tmp).ok();
}
}