乐于分享
好东西不私藏

OpenClaw工具拆解之sandboxed_write+sandboxed_edit

OpenClaw工具拆解之sandboxed_write+sandboxed_edit

一、sandboxed_write 工具

1.1 工具概述

功能:沙盒中写入文件
核心特性

  • • 通过 bridge 写入隔离文件系统
  • • 自动创建父目录
  • • 支持沙盒根目录限制
  • • 参数标准化包装

1.2 创建函数

位置:第 115006 行

functioncreateSandboxedWriteTool(params) {
returnwrapToolParamNormalization(createWriteTool(params.root, { 
operationscreateSandboxWriteOperations(params) 
    }), CLAUDE_PARAM_GROUPS.write);
}

1.3 沙盒写入操作

位置:第 115068 行

functioncreateSandboxWriteOperations(params) {
return {
// 1. 创建目录
mkdirasync (dir) => {
await params.bridge.mkdirp({
filePath: dir,
cwd: params.root
            });
        },

// 2. 写入文件
writeFileasync (absolutePath, content) => {
await params.bridge.writeFile({
filePath: absolutePath,
cwd: params.root,
data: content
            });
        }
    };
}

1.4 包装链

createWriteTool (外部库)
    ↓ (使用沙盒操作)
wrapToolParamNormalization (参数标准化)
    ↓ (CLAUDE_PARAM_GROUPS.write)
最终工具

1.5 参数标准化

constCLAUDE_PARAM_GROUPS = {
write: [
        {
keys: ["path""file_path""filePath""file"],
label"path alias"
        },
        {
keys: ["content"],
label"content"
        }
    ]
};

constCLAUDE_PARAM_ALIASES = [
    { original"path"alias"file_path" },
    { original"path"alias"filePath" },
    { original"path"alias"file" }
];

1.6 执行流程图

sandboxed_write 工具调用
    ↓
1. 参数标准化
   ├─ path/file_path/filePath/file → path
   └─ content → content
    ↓
2. 验证必填参数
    ↓
3. 沙盒桥接写入
    ├─ bridge.mkdirp(创建父目录)
    └─ bridge.writeFile(写入文件)
    ↓
4. 返回结果

1.7 返回结果格式

成功

{
"content":[{
"type":"text",
"text":"Successfully wrote 123 bytes to sandbox:src/main.js"
}],
"details":{
"path":"src/main.js",
"bytesWritten":123,
"sandbox":true
}
}

二、sandboxed_edit 工具

2.1 工具概述

功能:沙盒中编辑文件
核心特性

  • • 通过 bridge 访问隔离文件系统
  • • 支持编辑失败恢复
  • • 支持参数别名
  • • 精确文本替换

2.2 创建函数

位置:第 115009 行

functioncreateSandboxedEditTool(params) {
returnwrapToolParamNormalization(
wrapEditToolWithRecovery(createEditTool(params.root, { 
operationscreateSandboxEditOperations(params) 
        }), {
root: params.root,
readFileasync (absolutePath) => (await params.bridge.readFile({
filePath: absolutePath,
cwd: params.root
            })).toString("utf8")
        }), 
CLAUDE_PARAM_GROUPS.edit
    );
}

2.3 沙盒编辑操作

位置:第 115077 行

functioncreateSandboxEditOperations(params) {
return {
// 1. 读取文件
readFile(absolutePath) => params.bridge.readFile({
filePath: absolutePath,
cwd: params.root
        }),

// 2. 写入文件
writeFile(absolutePath, content) => params.bridge.writeFile({
filePath: absolutePath,
cwd: params.root,
data: content
        }),

// 3. 访问检查
accessasync (absolutePath) => {
if (!await params.bridge.stat({
filePath: absolutePath,
cwd: params.root
            })) {
throwcreateFsAccessError("ENOENT", absolutePath);
            }
        }
    };
}

2.4 编辑恢复包装

位置:第 114462 行

functionwrapEditToolWithRecovery(base, options) {
return {
        ...base,
executeasync (toolCallId, params, signal, onUpdate) => {
// 1. 读取参数
const { pathParam, oldText, newText } = readEditToolParams(params);

// 2. 解析绝对路径
const absolutePath = typeof pathParam === "string" ? 
resolveEditPath(options.root, pathParam) : void0;

// 3. 读取原始内容
let originalContent;
if (absolutePath && newText !== void0) {
try {
                    originalContent = await options.readFile(absolutePath);
                } catch {}
            }

// 4. 执行编辑
try {
returnawait base.execute(toolCallId, params, signal, onUpdate);
            } catch (err) {
// 5. 编辑失败处理
if (!absolutePath) throw err;

let currentContent;
try {
                    currentContent = await options.readFile(absolutePath);
                } catch {}

// 6. 判断编辑是否已应用
if (typeof currentContent === "string" && newText !== void0) {
if (didEditLikelyApply({
                        originalContent,
                        currentContent,
                        oldText,
                        newText
                    })) {
returnbuildEditSuccessResult(pathParam ?? absolutePath);
                    }
                }

// 7. 添加不匹配提示
if (typeof currentContent === "string" && 
                    err instanceofError && 
shouldAddMismatchHint(err)) {
throwappendMismatchHint(err, currentContent);
                }

throw err;
            }
        }
    };
}

2.5 参数标准化

constCLAUDE_PARAM_GROUPS = {
edit: [
        {
keys: ["path""file_path""filePath""file"],
label"path alias"
        },
        {
keys: ["oldText""old_string""old_text""oldString"],
label"oldText alias"
        },
        {
keys: ["newText""new_string""new_text""newString"],
label"newText alias",
allowEmptytrue
        }
    ]
};

constCLAUDE_PARAM_ALIASES = [
// path 别名
    { original"path"alias"file_path" },
    { original"path"alias"filePath" },
    { original"path"alias"file" },

// oldText 别名
    { original"oldText"alias"old_string" },
    { original"oldText"alias"old_text" },
    { original"oldText"alias"oldString" },

// newText 别名
    { original"newText"alias"new_string" },
    { original"newText"alias"new_text" },
    { original"newText"alias"newString" }
];

2.6 执行流程图

sandboxed_edit 工具调用
    ↓
1. 参数标准化
   ├─ path 别名处理
   ├─ oldText 别名处理
   └─ newText 别名处理
    ↓
2. 验证必填参数
    ↓
3. 读取原始内容
    ↓
4. 执行编辑(精确替换)
    ↓
5. 编辑失败处理
   ├─ 读取当前内容
   ├─ 判断是否部分成功
   └─ 添加不匹配提示
    ↓
6. 返回结果

三、关键机制对比

3.1 功能定位

特性
sandboxed_write
sandboxed_edit
用途
创建/覆盖文件
精确修改文件
写操作
覆盖写入
精确替换
恢复机制
不支持
支持

3.2 参数支持

特性
sandboxed_write
sandboxed_edit
参数别名
4 个(path)
9 个(path/oldText/newText)
必填参数
path, content
path, oldText
可选参数
newText(可为空)

3.3 安全限制

限制类型
sandboxed_write
sandboxed_edit
沙盒根目录
root 限制
root 限制
桥接访问
必需
必需
路径边界
bridge 路径
bridge 路径

四、沙盒工具系列总结

4.1 三个沙盒工具

工具
功能
桥接操作
sandboxed_read
读取文件
bridge.readFile, bridge.stat, detectMime
sandboxed_write
写入文件
bridge.mkdirp, bridge.writeFile
sandboxed_edit
编辑文件
bridge.readFile, bridge.writeFile, bridge.stat

4.2 共同特点

  • • 通过 bridge 访问隔离文件系统
  • • 不能直接访问 host 文件系统
  • • 用于容器/Docker/沙盒环境
  • • 支持 modelContextWindowTokens 限制
  • • 支持图片 sanitization

4.3 使用场景

沙盒模式启用时:
├─ 读取文件 → sandboxed_read
├─ 写入文件 → sandboxed_write
└─ 编辑文件 → sandboxed_edit

非沙盒模式时:
├─ 读取文件 → read
├─ 写入文件 → write
└─ 编辑文件 → edit

五、使用示例

5.1 sandboxed_write 工具调用

用户在沙盒中创建文件

大模型返回

{
"tool_call":{
"name":"sandboxed_write",
"arguments":{
"path":"src/main.js",
"content":"console.log(\"Hello\");"
}
}
}

执行结果

{
"content":[{
"type":"text",
"text":"Successfully wrote 27 bytes to sandbox:src/main.js"
}],
"details":{
"path":"src/main.js",
"bytesWritten":27,
"sandbox":true
}
}

5.2 sandboxed_edit 工具调用

用户修改沙盒中的文件

大模型返回

{
"tool_call":{
"name":"sandboxed_edit",
"arguments":{
"path":"src/main.js",
"oldText":"console.log(\"Hello\");",
"newText":"console.log(\"Hello, World!\");"
}
}
}

执行结果

{
"content":[{
"type":"text",
"text":"Successfully edited sandbox:src/main.js"
}],
"details":{
"path":"src/main.js",
"sandbox":true
}
}