新增: 断点续跑与日志租约底座
This commit is contained in:
@@ -393,6 +393,16 @@ pub fn register(
|
||||
anyhow::bail!("写入内容超过 1MB 限制 ({} 字节)", bytes.len());
|
||||
}
|
||||
let target = std::path::Path::new(path);
|
||||
// R12(2026-10-05):读取旧内容供 diff 回看(仅 utf-8 且旧文件存在且 ≤1MB;
|
||||
// base64 二进制/新建文件无 diff 语义,跳过。读取在写入前完成,与 rename 不竞态)
|
||||
let old_content_for_diff: Option<String> = if encoding.eq_ignore_ascii_case("utf-8") {
|
||||
match tokio::fs::read_to_string(target).await {
|
||||
Ok(s) if s.len() <= 1_048_576 => Some(s),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// FR-S7 覆盖防护:覆盖非空文件前自动 .bak 备份(防 LLM 误用 write_file 当 edit 致数据彻底丢失)
|
||||
// 起因:会话 3473fcb7 AI 误传头部 3 行把 PROGRESS.md 762 行/72KB 覆盖成 248 字节
|
||||
let old_size: Option<u64> = match tokio::fs::metadata(target).await {
|
||||
@@ -438,7 +448,14 @@ pub fn register(
|
||||
tracing::warn!("write_file 疑似误覆盖: {} {}→{} 字节(缩减>90%),.bak 已备份", path, old, bytes.len());
|
||||
}
|
||||
}
|
||||
Ok(serde_json::json!({ "path": path, "bytes_written": bytes.len(), "old_size": old_size, "encoding": encoding }))
|
||||
// R12:行级 unified diff(旧 vs 新,同 patch_file 的 generate_diff;新建文件/base64 为 null 前端不渲染)
|
||||
let diff_json = match old_content_for_diff {
|
||||
Some(old) if encoding.eq_ignore_ascii_case("utf-8") => {
|
||||
serde_json::Value::String(generate_diff(&old, &raw))
|
||||
}
|
||||
_ => serde_json::Value::Null,
|
||||
};
|
||||
Ok(serde_json::json!({ "path": path, "bytes_written": bytes.len(), "old_size": old_size, "encoding": encoding, "diff": diff_json }))
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ pub(crate) fn caller_conv() -> Option<String> {
|
||||
|
||||
// ── 参数解析与任务书组装(纯函数,单测锁定) ──
|
||||
|
||||
/// 解析 max_rounds:缺省默认 6,合法域钳制 [1, 20](防参数放大预算失控)。
|
||||
/// 解析 max_rounds:缺省默认 12,合法域钳制 [1, 20](防参数放大预算失控)。
|
||||
fn parse_max_rounds(raw: Option<u64>) -> u32 {
|
||||
raw.map(|v| v as u32)
|
||||
.unwrap_or(SUB_AGENT_DEFAULT_MAX_ROUNDS)
|
||||
@@ -153,7 +153,7 @@ pub fn register(registry: &mut AiToolRegistry, ctx: SpawnAgentCtx) {
|
||||
},
|
||||
"max_rounds": {
|
||||
"type": "integer",
|
||||
"description": "可选,工具循环轮数上限,默认 6,最大 20"
|
||||
"description": "可选,工具循环轮数上限,默认 12,最大 20"
|
||||
},
|
||||
"model": {
|
||||
"type": "string",
|
||||
@@ -166,7 +166,7 @@ pub fn register(registry: &mut AiToolRegistry, ctx: SpawnAgentCtx) {
|
||||
registry,
|
||||
ctx: SpawnAgentCtx,
|
||||
"spawn_agent",
|
||||
"派发一个子代理在隔离上下文中独立完成专项任务(不与用户交互),最终返回结论报告。适用:探索检索/多文件阅读汇总/资料核对等可独立收敛的子任务。参数 task 为自包含任务书(子代理看不到父对话);tools 为可选工具白名单;max_rounds 可选轮数上限(默认 6);model 可选模型(缺省继承当前会话)。注意:子代理无审批通道,写文件/命令执行等高风险工具会被自动拒绝,结论以 report 字段文本返回",
|
||||
"派发一个子代理在隔离上下文中独立完成专项任务(不与用户交互),最终返回结论报告。适用:探索检索/多文件阅读汇总/资料核对等可独立收敛的子任务。参数 task 为自包含任务书(子代理看不到父对话);tools 为可选工具白名单;max_rounds 可选轮数上限(默认 12);model 可选模型(缺省继承当前会话)。注意:子代理无审批通道,写文件/命令执行等高风险工具会被自动拒绝,结论以 report 字段文本返回",
|
||||
RiskLevel::Medium,
|
||||
meta: ToolMeta {
|
||||
// 审批卡文案模板(模板 {} 按位置填充,键取 task)
|
||||
|
||||
Reference in New Issue
Block a user