登记素材导入失败消息做长度收口,完整报告仍留在 typed 错误

- to_user_msg 对 ImportFailed/ImportPartial 先报成功/失败计数,再附有界 JSON 明细

- 新增 IMPORT_REPORT_MESSAGE_MAX_CHARS=4000 字符上限

- 补 TODO:应由工具选择性返回,或把完整报告重定向到文件/诊断日志
This commit is contained in:
2026-10-02 14:58:37 +08:00
parent 9c7cf2601c
commit e7adefb0a1
@@ -112,8 +112,12 @@ impl ToolFailure for ImportAccountAssetsError {
Self::NoImportSource => {
"登记素材失败:至少提供一个非空的 assetIds 或 localPaths 数组。".to_string()
}
Self::ImportFailed { report } => format!("登记素材失败:{report}"),
Self::ImportPartial { report } => format!("登记素材部分成功:{report}"),
Self::ImportFailed { report } => {
format!("登记素材失败:{}", import_report_message(report))
}
Self::ImportPartial { report } => {
format!("登记素材部分成功:{}", import_report_message(report))
}
}
}
@@ -124,3 +128,29 @@ impl ToolFailure for ImportAccountAssetsError {
}
}
}
/// 逐项导入结果写进消息时的字符上限。
///
/// 完整 `report` 仍留在 typed 错误里(诊断 sidecar 落的是原文),这里只收口给模型/用户
/// 看的那一句话。
const IMPORT_REPORT_MESSAGE_MAX_CHARS: usize = 4_000;
/// 把逐项导入结果压成一句话:先报成功/失败计数,再附有界 JSON 明细。
fn import_report_message(report: &Value) -> String {
let imported = report
.get("imported")
.and_then(Value::as_array)
.map_or(0, |items| items.len());
let failures = report
.get("failures")
.and_then(Value::as_array)
.map_or(0, |items| items.len());
// TODO(工具设计):这里仍把整份 report 序列化进消息,只是按字符数收口兜底。正确方向是让
// 工具自己做选择性返回——消息只带计数 + 可操作的失败项;或允许把完整报告重定向到文件/
// 诊断日志,消息里只留引用,避免几十 KB 的逐项结果挤占模型上下文。
let detail = crate::agent::redaction::truncate_agent_runtime_text(
&report.to_string(),
IMPORT_REPORT_MESSAGE_MAX_CHARS,
);
format!("成功 {imported} 项、失败 {failures} 项:{detail}")
}