mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 19:45:34 +08:00
fix: parse tool_use/tool_result messages and add OpenCode SQLite backend (#1401)
* fix: parse tool_use/tool_result messages and add OpenCode SQLite backend - Claude: reclassify user messages containing tool_result as "tool" role - Codex: handle function_call and function_call_output payload types - Gemini: support array content and toolCalls extraction, filter info/error types - OpenCode: add SQLite session scan, load and delete alongside legacy JSON - utils: extend parse_timestamp_to_ms for integer timestamps, extract tool_use/tool_result in shared extract_text * fix: address remaining issues from tool_use/tool_result parsing commit - Claude: fix role misclassification for mixed user+tool_result messages (any → all) - OpenCode: extract duplicate part text logic into extract_part_text() - OpenCode: add path validation for SQLite delete to prevent foreign DB access - OpenCode: wrap SQLite deletion in transaction for atomicity - openclaw_config: remove redundant as_deref() on Option<&str>
This commit is contained in:
@@ -52,11 +52,25 @@ pub fn load_messages(path: &Path) -> Result<Vec<SessionMessage>, String> {
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let role = message
|
||||
let mut role = message
|
||||
.get("role")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
|
||||
// Claude wraps tool_result inside user messages; reclassify as "tool" role
|
||||
if role == "user" {
|
||||
if let Some(Value::Array(items)) = message.get("content") {
|
||||
let all_tool_results = !items.is_empty()
|
||||
&& items.iter().all(|item| {
|
||||
item.get("type").and_then(Value::as_str) == Some("tool_result")
|
||||
});
|
||||
if all_tool_results {
|
||||
role = "tool".to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let content = message.get("content").map(extract_text).unwrap_or_default();
|
||||
if content.trim().is_empty() {
|
||||
continue;
|
||||
@@ -268,4 +282,58 @@ mod tests {
|
||||
assert!(!path.exists());
|
||||
assert!(!sidecar.exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_messages_tool_use_shows_as_assistant() {
|
||||
let temp = tempdir().expect("tempdir");
|
||||
let path = temp.path().join("session.jsonl");
|
||||
std::fs::write(
|
||||
&path,
|
||||
concat!(
|
||||
"{\"message\":{\"role\":\"assistant\",\"content\":[{\"type\":\"tool_use\",\"id\":\"toolu_1\",\"name\":\"Write\",\"input\":{\"file_path\":\"a.txt\"}}]},\"timestamp\":\"2026-03-06T10:00:00Z\"}\n",
|
||||
"{\"message\":{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_1\",\"content\":\"File written\"}]},\"timestamp\":\"2026-03-06T10:00:01Z\"}\n",
|
||||
),
|
||||
)
|
||||
.expect("write");
|
||||
|
||||
let msgs = load_messages(&path).expect("load");
|
||||
assert_eq!(msgs.len(), 2);
|
||||
assert_eq!(msgs[0].role, "assistant");
|
||||
assert!(msgs[0].content.contains("[Tool: Write]"));
|
||||
assert_eq!(msgs[1].role, "tool");
|
||||
assert_eq!(msgs[1].content, "File written");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_messages_mixed_text_and_tool_use() {
|
||||
let temp = tempdir().expect("tempdir");
|
||||
let path = temp.path().join("session.jsonl");
|
||||
std::fs::write(
|
||||
&path,
|
||||
"{\"message\":{\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"Let me help.\"},{\"type\":\"tool_use\",\"id\":\"toolu_1\",\"name\":\"Read\",\"input\":{}}]},\"timestamp\":\"2026-03-06T10:00:00Z\"}\n",
|
||||
)
|
||||
.expect("write");
|
||||
|
||||
let msgs = load_messages(&path).expect("load");
|
||||
assert_eq!(msgs.len(), 1);
|
||||
assert_eq!(msgs[0].role, "assistant");
|
||||
assert!(msgs[0].content.contains("Let me help."));
|
||||
assert!(msgs[0].content.contains("[Tool: Read]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_messages_mixed_user_tool_result_and_text_stays_user() {
|
||||
let temp = tempdir().expect("tempdir");
|
||||
let path = temp.path().join("session.jsonl");
|
||||
std::fs::write(
|
||||
&path,
|
||||
"{\"message\":{\"role\":\"user\",\"content\":[{\"type\":\"tool_result\",\"tool_use_id\":\"toolu_1\",\"content\":\"result\"},{\"type\":\"text\",\"text\":\"Please continue\"}]},\"timestamp\":\"2026-03-06T10:00:00Z\"}\n",
|
||||
)
|
||||
.expect("write");
|
||||
|
||||
let msgs = load_messages(&path).expect("load");
|
||||
assert_eq!(msgs.len(), 1);
|
||||
assert_eq!(msgs[0].role, "user");
|
||||
assert!(msgs[0].content.contains("Please continue"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user