OpenClaw工具拆解之host_workspace_write+host_workspace_edit
一、host_workspace_write 工具
1.1 工具概述
功能:写入 host 工作区文件
核心特性:
-
• 直接访问 host 文件系统 -
• 支持 workspaceOnly 限制 -
• 自动创建父目录 -
• 参数标准化包装 -
• 边界检查
1.2 创建函数
位置:第 115018 行
functioncreateHostWorkspaceWriteTool(root, options) {
returnwrapToolParamNormalization(createWriteTool(root, {
operations: createHostWriteOperations(root, options)
}), CLAUDE_PARAM_GROUPS.write);
}
1.3 Host 写入操作
位置:第 115057 行
asyncfunctionwriteHostFile(absolutePath, content) {
const resolved = path.resolve(absolutePath);
await fs$1.mkdir(path.dirname(resolved), { recursive: true });
await fs$1.writeFile(resolved, content, "utf-8");
}
functioncreateHostWriteOperations(root, options) {
// 1. 无限制模式
if (!(options?.workspaceOnly ?? false)) {
return {
mkdir: async (dir) => {
const resolved = path.resolve(dir);
await fs$1.mkdir(resolved, { recursive: true });
},
writeFile: writeHostFile
};
}
// 2. workspaceOnly 模式(限制只能访问工作区)
return {
mkdir: async (dir) => {
const relative = toRelativeWorkspacePath(root, dir, { allowRoot: true });
const resolved = relative ? path.resolve(root, relative) : path.resolve(root);
awaitassertSandboxPath({
filePath: resolved,
cwd: root,
root
});
await fs$1.mkdir(resolved, { recursive: true });
},
writeFile: async (absolutePath, content) => {
awaitwriteFileWithinRoot({
rootDir: root,
relativePath: toRelativeWorkspacePath(root, absolutePath),
data: content,
mkdir: true
});
}
};
}
1.4 包装链
createWriteTool (外部库)
↓ (使用 Host 操作)
wrapToolParamNormalization (参数标准化)
↓ (CLAUDE_PARAM_GROUPS.write)
最终工具
1.5 workspaceOnly 模式
// workspaceOnly = false(无限制)
├─ 可以写入任意路径
└─ 直接调用 fs.mkdir/fs.writeFile
// workspaceOnly = true(限制模式)
├─ 只能写入工作区内
├─ assertSandboxPath 检查边界
└─ writeFileWithinRoot 安全写入
1.6 执行流程图
host_workspace_write 工具调用
↓
1. 参数标准化
├─ path/file_path/filePath/file → path
└─ content → content
↓
2. 验证必填参数
↓
3. 检查 workspaceOnly 限制
├─ 是 → 验证路径在工作区内
└─ 否 → 允许任意路径
↓
4. 创建父目录(mkdir -p)
↓
5. 写入文件(覆盖模式)
↓
6. 返回结果
二、host_workspace_edit 工具
2.1 工具概述
功能:编辑 host 工作区文件
核心特性:
-
• 直接访问 host 文件系统 -
• 支持 workspaceOnly 限制 -
• 支持编辑失败恢复 -
• 参数标准化包装 -
• 边界检查
2.2 创建函数
位置:第 115021 行
functioncreateHostWorkspaceEditTool(root, options) {
returnwrapToolParamNormalization(
wrapEditToolWithRecovery(createEditTool(root, {
operations: createHostEditOperations(root, options)
}), {
root,
readFile: (absolutePath) => fs$1.readFile(absolutePath, "utf-8")
}),
CLAUDE_PARAM_GROUPS.edit
);
}
2.3 Host 编辑操作
位置:第 115099 行
functioncreateHostEditOperations(root, options) {
// 1. 无限制模式
if (!(options?.workspaceOnly ?? false)) {
return {
readFile: async (absolutePath) => {
const resolved = path.resolve(absolutePath);
returnawait fs$1.readFile(resolved);
},
writeFile: writeHostFile,
access: async (absolutePath) => {
const resolved = path.resolve(absolutePath);
await fs$1.access(resolved);
}
};
}
// 2. workspaceOnly 模式(限制只能访问工作区)
return {
readFile: async (absolutePath) => {
return (awaitreadFileWithinRoot({
rootDir: root,
relativePath: toRelativeWorkspacePath(root, absolutePath)
})).buffer;
},
writeFile: async (absolutePath, content) => {
awaitwriteFileWithinRoot({
rootDir: root,
relativePath: toRelativeWorkspacePath(root, absolutePath),
data: content,
mkdir: true
});
},
access: async (absolutePath) => {
let relative;
try {
relative = toRelativeWorkspacePath(root, absolutePath);
} catch {
return;
}
try {
await (awaitopenFileWithinRoot({
rootDir: root,
relativePath: relative
})).fd;
} catch {
// 忽略错误
}
}
};
}
2.4 编辑恢复包装
位置:第 114462 行(与 sandboxed_edit 共享)
functionwrapEditToolWithRecovery(base, options) {
return {
...base,
execute: async (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",
allowEmpty: true
}
]
};
2.6 执行流程图
host_workspace_edit 工具调用
↓
1. 参数标准化
├─ path 别名处理
├─ oldText 别名处理
└─ newText 别名处理
↓
2. 验证必填参数
↓
3. 检查 workspaceOnly 限制
↓
4. 读取原始内容
↓
5. 执行编辑(精确替换)
↓
6. 编辑失败处理
├─ 读取当前内容
├─ 判断是否部分成功
└─ 添加不匹配提示
↓
7. 返回结果
三、关键机制对比
3.1 功能定位
|
|
|
|
| 用途 |
|
|
| 写操作 |
|
|
| 恢复机制 |
|
|
3.2 与沙盒工具对比
|
|
|
|
| 文件系统 |
|
|
| 性能 |
|
|
| 安全性 |
|
|
| 使用场景 |
|
|
3.3 workspaceOnly 模式
// workspaceOnly = false
├─ 可以访问任意路径
├─ 直接调用 fs 模块
└─ 无边界检查
// workspaceOnly = true
├─ 只能访问工作区
├─ assertSandboxPath 检查
├─ writeFileWithinRoot 安全写入
└─ readFileWithinRoot 安全读取
四、Host 工具系列总结
4.1 两个 Host 工具
|
|
|
|
| host_workspace_write |
|
|
| host_workspace_edit |
|
|
4.2 共同特点
-
• 直接访问 host 文件系统 -
• 支持 workspaceOnly 限制 -
• 自动创建父目录 -
• 参数标准化(CLAUDE 别名) -
• 边界检查(workspaceOnly 模式)
4.3 使用场景
非沙盒模式时:
├─ 读取文件 → read (或 host_workspace_read 如果存在)
├─ 写入文件 → host_workspace_write
└─ 编辑文件 → host_workspace_edit
沙盒模式时:
├─ 读取文件 → sandboxed_read
├─ 写入文件 → sandboxed_write
└─ 编辑文件 → sandboxed_edit
五、使用示例
5.1 host_workspace_write 工具调用
用户:在工作区创建文件
大模型返回:
{
"tool_call":{
"name":"host_workspace_write",
"arguments":{
"path":"src/main.js",
"content":"console.log(\"Hello\");"
}
}
}
执行结果:
{
"content":[{
"type":"text",
"text":"Successfully wrote 27 bytes to src/main.js"
}],
"details":{
"path":"src/main.js",
"bytesWritten":27,
"workspaceOnly":true
}
}
5.2 host_workspace_edit 工具调用
用户:修改工作区中的文件
大模型返回:
{
"tool_call":{
"name":"host_workspace_edit",
"arguments":{
"path":"src/main.js",
"oldText":"console.log(\"Hello\");",
"newText":"console.log(\"Hello, World!\");"
}
}
}
执行结果:
{
"content":[{
"type":"text",
"text":"Successfully edited src/main.js"
}],
"details":{
"path":"src/main.js",
"workspaceOnly":true
}
}
夜雨聆风