mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-01 12:22:09 +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:
@@ -59,16 +59,37 @@ pub fn load_messages(path: &Path) -> Result<Vec<SessionMessage>, String> {
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if payload.get("type").and_then(Value::as_str) != Some("message") {
|
||||
continue;
|
||||
}
|
||||
let payload_type = payload.get("type").and_then(Value::as_str).unwrap_or("");
|
||||
|
||||
// Codex uses separate payload types for tool interactions
|
||||
let (role, content) = match payload_type {
|
||||
"message" => {
|
||||
let role = payload
|
||||
.get("role")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
let content = payload.get("content").map(extract_text).unwrap_or_default();
|
||||
(role, content)
|
||||
}
|
||||
"function_call" => {
|
||||
let name = payload
|
||||
.get("name")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("unknown");
|
||||
("assistant".to_string(), format!("[Tool: {name}]"))
|
||||
}
|
||||
"function_call_output" => {
|
||||
let output = payload
|
||||
.get("output")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
("tool".to_string(), output)
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let role = payload
|
||||
.get("role")
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
let content = payload.get("content").map(extract_text).unwrap_or_default();
|
||||
if content.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
@@ -239,4 +260,36 @@ mod tests {
|
||||
|
||||
assert!(!path.exists());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_messages_includes_function_call_and_output() {
|
||||
let temp = tempdir().expect("tempdir");
|
||||
let path = temp.path().join("session.jsonl");
|
||||
std::fs::write(
|
||||
&path,
|
||||
concat!(
|
||||
"{\"timestamp\":\"2026-03-06T21:50:12Z\",\"type\":\"session_meta\",\"payload\":{\"id\":\"test-id\",\"cwd\":\"/tmp\"}}\n",
|
||||
"{\"timestamp\":\"2026-03-06T21:50:13Z\",\"type\":\"response_item\",\"payload\":{\"type\":\"message\",\"role\":\"user\",\"content\":\"list files\"}}\n",
|
||||
"{\"timestamp\":\"2026-03-06T21:50:14Z\",\"type\":\"response_item\",\"payload\":{\"type\":\"function_call\",\"name\":\"shell\",\"arguments\":\"{\\\"cmd\\\":[\\\"ls\\\"]}\",\"call_id\":\"call_1\"}}\n",
|
||||
"{\"timestamp\":\"2026-03-06T21:50:15Z\",\"type\":\"response_item\",\"payload\":{\"type\":\"function_call_output\",\"call_id\":\"call_1\",\"output\":\"file1.txt\\nfile2.txt\"}}\n",
|
||||
"{\"timestamp\":\"2026-03-06T21:50:16Z\",\"type\":\"response_item\",\"payload\":{\"type\":\"message\",\"role\":\"assistant\",\"content\":[{\"type\":\"output_text\",\"text\":\"Done.\"}]}}\n",
|
||||
),
|
||||
)
|
||||
.expect("write");
|
||||
|
||||
let msgs = load_messages(&path).expect("load");
|
||||
assert_eq!(msgs.len(), 4);
|
||||
|
||||
assert_eq!(msgs[0].role, "user");
|
||||
assert_eq!(msgs[0].content, "list files");
|
||||
|
||||
assert_eq!(msgs[1].role, "assistant");
|
||||
assert!(msgs[1].content.contains("[Tool: shell]"));
|
||||
|
||||
assert_eq!(msgs[2].role, "tool");
|
||||
assert!(msgs[2].content.contains("file1.txt"));
|
||||
|
||||
assert_eq!(msgs[3].role, "assistant");
|
||||
assert_eq!(msgs[3].content, "Done.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user