OpenClaw工具拆解之host_workspace_write+host_workspace_edit

一、host_workspace_write 工具

1.1 工具概述

功能 :写入 host 工作区文件
核心特性:

  • 直接访问 host 文件系统
  • 支持 workspaceOnly 限制
  • 自动创建父目录
  • 参数标准化包装
  • 边界检查

1.2 创建函数

位置:第 115018 行

javascript 复制代码
function createHostWorkspaceWriteTool(root, options) {
    return wrapToolParamNormalization(createWriteTool(root, { 
        operations: createHostWriteOperations(root, options) 
    }), CLAUDE_PARAM_GROUPS.write);
}

1.3 Host 写入操作

位置:第 115057 行

javascript 复制代码
async function writeHostFile(absolutePath, content) {
    const resolved = path.resolve(absolutePath);
    await fs$1.mkdir(path.dirname(resolved), { recursive: true });
    await fs$1.writeFile(resolved, content, "utf-8");
}

function createHostWriteOperations(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);
            await assertSandboxPath({
                filePath: resolved,
                cwd: root,
                root
            });
            await fs$1.mkdir(resolved, { recursive: true });
        },
        writeFile: async (absolutePath, content) => {
            await writeFileWithinRoot({
                rootDir: root,
                relativePath: toRelativeWorkspacePath(root, absolutePath),
                data: content,
                mkdir: true
            });
        }
    };
}

1.4 包装链

复制代码
createWriteTool (外部库)
    ↓ (使用 Host 操作)
wrapToolParamNormalization (参数标准化)
    ↓ (CLAUDE_PARAM_GROUPS.write)
最终工具

1.5 workspaceOnly 模式

javascript 复制代码
// 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 行

javascript 复制代码
function createHostWorkspaceEditTool(root, options) {
    return wrapToolParamNormalization(
        wrapEditToolWithRecovery(createEditTool(root, { 
            operations: createHostEditOperations(root, options) 
        }), {
            root,
            readFile: (absolutePath) => fs$1.readFile(absolutePath, "utf-8")
        }), 
        CLAUDE_PARAM_GROUPS.edit
    );
}

2.3 Host 编辑操作

位置:第 115099 行

javascript 复制代码
function createHostEditOperations(root, options) {
    // 1. 无限制模式
    if (!(options?.workspaceOnly ?? false)) {
        return {
            readFile: async (absolutePath) => {
                const resolved = path.resolve(absolutePath);
                return await 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 (await readFileWithinRoot({
                rootDir: root,
                relativePath: toRelativeWorkspacePath(root, absolutePath)
            })).buffer;
        },
        writeFile: async (absolutePath, content) => {
            await writeFileWithinRoot({
                rootDir: root,
                relativePath: toRelativeWorkspacePath(root, absolutePath),
                data: content,
                mkdir: true
            });
        },
        access: async (absolutePath) => {
            let relative;
            try {
                relative = toRelativeWorkspacePath(root, absolutePath);
            } catch {
                return;
            }
            try {
                await (await openFileWithinRoot({
                    rootDir: root,
                    relativePath: relative
                })).fd;
            } catch {
                // 忽略错误
            }
        }
    };
}

2.4 编辑恢复包装

位置:第 114462 行(与 sandboxed_edit 共享)

javascript 复制代码
function wrapEditToolWithRecovery(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) : void 0;
            
            // 3. 读取原始内容
            let originalContent;
            if (absolutePath && newText !== void 0) {
                try {
                    originalContent = await options.readFile(absolutePath);
                } catch {}
            }
            
            // 4. 执行编辑
            try {
                return await 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 !== void 0) {
                    if (didEditLikelyApply({
                        originalContent,
                        currentContent,
                        oldText,
                        newText
                    })) {
                        return buildEditSuccessResult(pathParam ?? absolutePath);
                    }
                }
                
                // 7. 添加不匹配提示
                if (typeof currentContent === "string" && 
                    err instanceof Error && 
                    shouldAddMismatchHint(err)) {
                    throw appendMismatchHint(err, currentContent);
                }
                
                throw err;
            }
        }
    };
}

2.5 参数标准化

javascript 复制代码
const CLAUDE_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 功能定位

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

3.2 与沙盒工具对比

特性 Host 工具 沙盒工具
文件系统 Host 直接访问 Bridge 隔离访问
性能 更快 桥接开销
安全性 较低 较高
使用场景 非沙盒模式 沙盒模式

3.3 workspaceOnly 模式

javascript 复制代码
// workspaceOnly = false
├─ 可以访问任意路径
├─ 直接调用 fs 模块
└─ 无边界检查

// workspaceOnly = true
├─ 只能访问工作区
├─ assertSandboxPath 检查
├─ writeFileWithinRoot 安全写入
└─ readFileWithinRoot 安全读取

四、Host 工具系列总结

4.1 两个 Host 工具

工具 功能 操作
host_workspace_write 写入 Host 文件 fs.mkdir, fs.writeFile
host_workspace_edit 编辑 Host 文件 fs.readFile, fs.writeFile, fs.access

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 工具调用

用户 :在工作区创建文件

大模型返回:

json 复制代码
{
  "tool_call": {
    "name": "host_workspace_write",
    "arguments": { 
      "path": "src/main.js",
      "content": "console.log(\"Hello\");"
    }
  }
}

执行结果:

json 复制代码
{
  "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 工具调用

用户 :修改工作区中的文件

大模型返回:

json 复制代码
{
  "tool_call": {
    "name": "host_workspace_edit",
    "arguments": { 
      "path": "src/main.js",
      "oldText": "console.log(\"Hello\");",
      "newText": "console.log(\"Hello, World!\");"
    }
  }
}

执行结果:

json 复制代码
{
  "content": [{
    "type": "text",
    "text": "Successfully edited src/main.js"
  }],
  "details": {
    "path": "src/main.js",
    "workspaceOnly": true
  }
}
相关推荐
IT_陈寒3 分钟前
Java序列化踩坑记:对象循环引用让我加班两小时
前端·人工智能·后端
ZhengEnCi6 分钟前
同样的模型,为什么本地和云 API 差别那么大:量化精度、聊天模板与采样参数的三大元凶
人工智能·算法·llm
vilya12 分钟前
Agent 语音引擎换心记:从「够用」到「稳且好」
人工智能·agent
王中阳Go13 分钟前
5.27 分钟干完后端和全部测试:一场三小时笔试的五个失分点,四个不在代码上
大数据·数据库·人工智能·后端·大语言模型
70后写java的老码农14 分钟前
Ollama 大模型私有化部署与彻底卸载指南(Windows/Linux)
人工智能
清如许.17 分钟前
如何评估 AI 智能体(AI Agent)?指标、方法与最佳实践
人工智能
猪八宅百炼成仙18 分钟前
让 AI 帮你清理电脑而不翻车:一个 Windows 体检调优 Skill 的工程化设计
人工智能·windows
Acro18 分钟前
快给macOS 上的Grok Bot换一套皮肤
前端
宋艳_AI应用开发19 分钟前
五个阶段跑完,它交了一份日期错两年的投资报告——深思熟虑的Agent最危险的地方,是想得太像
人工智能
flash俊杰20 分钟前
双引擎 OCR 编排:逐页判定、视觉优先、partial 语义与三层超时
前端