清理: 停滞判定工具名映射构建去重

两处重复的 id 到 name 映射抽共用 helper
This commit is contained in:
lxy
2026-10-01 08:28:07 +08:00
parent 57d9fd8ad3
commit e3a8a8cffb
@@ -80,25 +80,14 @@ pub(crate) async fn count_recent_failures(
if recent_tool_results.is_empty() {
return (0u32, String::new());
}
// tool_call_id → tool_name 反查表:遍历 Assistant 消息的 tool_calls(开销与消息数线性)。
// tool_result 消息只带 tool_call_id,工具名在其前驱 Assistant 头里。
let mut id_to_name: std::collections::HashMap<&str, &str> = std::collections::HashMap::new();
for m in &messages {
if let MessageRole::Assistant = m.role {
if let Some(calls) = m.tool_calls.as_ref() {
for c in calls {
id_to_name.insert(c.id.as_str(), c.function.name.as_str());
}
}
}
}
let id_to_name = build_id_to_name(&messages);
// 本轮失败的归一 key 追加进窗口(顺序:消息正序,即工具执行顺序)。
for m in recent_tool_results.into_iter().rev() {
if is_failure_content(&m.content) {
let tool_name = m
.tool_call_id
.as_deref()
.and_then(|id| id_to_name.get(id).copied())
.and_then(|id| id_to_name.get(id).map(|s| s.as_str()))
.unwrap_or("unknown_tool");
let key = failure_key(tool_name, &m.content);
fail_window.push_back(key);
@@ -151,6 +140,24 @@ fn failure_key(tool_name: &str, content: &str) -> String {
format!("{}::{}:{:08x}", tool_name, bucket, h)
}
/// 构建 tool_call_id → tool_name 反查表(断路器失败分组与 tool_result 摘要压缩共用)。
///
/// Tool 结果消息只带 tool_call_id,真实工具名在前驱 Assistant 消息的
/// tool_calls[].function.name 里;查不到的 id 由调用方按各自语义兜底。
fn build_id_to_name(messages: &[ChatMessage]) -> std::collections::HashMap<String, String> {
let mut id_to_name = std::collections::HashMap::new();
for m in messages {
if let MessageRole::Assistant = m.role {
if let Some(calls) = m.tool_calls.as_ref() {
for c in calls {
id_to_name.insert(c.id.clone(), c.function.name.clone());
}
}
}
}
id_to_name
}
/// a 32-bit 哈希(零依赖,纯函数,断路器 key 归一专用;非密码学用途)。
fn fnv1a_32(bytes: &[u8]) -> u32 {
let mut hash: u32 = 0x811c9dc5;
@@ -227,21 +234,10 @@ pub(crate) fn summarize_tool_results(
let mut original_bytes: usize = 0;
let mut summarized_count: usize = 0;
// 构建 tool_call_id -> tool_name 映射:role=Tool 消息只带 tool_call_id(调用 ID),
// 真实工具名(read_file/run_command/...)在前序 role=Assistant 消息的 tool_calls[].function.name。
// 旧实现误把 tool_call_id(如 call_f892)当 tool_name 传给 extract_key_info,导致:
// 1) 摘要头注释显示 call_f892 而非 read_file(显示 bug);
// 2) extract_key_info 的 read_file 豁免永远命中不了(传入的不是真实名)。
// 用 owned String(非 &str 借用)避开与 messages.into_iter() 的所有权冲突;
// tool_call 数量极少(单轮几次),克隆开销可忽略。
let mut id_to_name: std::collections::HashMap<String, String> = std::collections::HashMap::new();
for m in &messages {
if let Some(calls) = m.tool_calls.as_ref() {
for c in calls {
id_to_name.insert(c.id.clone(), c.function.name.clone());
}
}
}
// tool_call_id → tool_name 反查与断路器共用 build_id_to_name;查不到(异常/老数据)
// 退化为 "tool"。旧实现曾误把 tool_call_id 当工具名,致摘要头显示 call_f892、
// read_file 豁免永远命中不了。
let id_to_name = build_id_to_name(&messages);
let msgs: Vec<ChatMessage> = messages
.into_iter()