文件操作和命令执行的抽象层,对标 DeepAgents BackendProtocol。
Sandbox behaviour 将工具层(ReadFile/WriteFile/Shell 等)与底层执行环境解耦, 支持在不同环境下替换实现(本地 OS、Docker 容器、远程沙箱等), 而不需要修改任何工具代码。
默认实现
CMDC.Sandbox.Local — 直接调用本地操作系统,适合开发和受信任环境。
自定义实现示例
defmodule MyApp.DockerSandbox do
@behaviour CMDC.Sandbox
@impl true
def read_file(path, opts) do
working_dir = Keyword.get(opts, :working_dir, ".")
# 在 Docker 容器内读取文件
docker_exec("cat #{Path.join(working_dir, path)}")
end
# ... 其他回调实现
end工具层透明代理模式
def execute(args, %{sandbox: sandbox} = ctx) when not is_nil(sandbox) do
sandbox.execute(args["command"], working_dir: ctx.working_dir)
end
def execute(args, ctx) do
CMDC.Sandbox.Local.execute(args["command"], working_dir: ctx.working_dir)
end选项
所有回调均接受 opts keyword list,常见选项:
:working_dir— 操作相对目录,默认".":timeout— 超时毫秒数(仅execute/2适用):offset— 读取偏移行数(仅read_file/2适用):limit— 读取最大行数(仅read_file/2适用)
Summary
Callbacks
精确字符串替换文件内容(str_replace 模式)。
执行 shell 命令。
检查文件或目录是否存在。
在指定路径下搜索匹配 glob 模式的文件。
在指定路径下搜索匹配正则模式的文件行。
列出目录内容。
读取文件内容。
写入文件内容(覆盖)。若父目录不存在则自动创建。
Types
@type dir_entry() :: %{ name: String.t(), type: :file | :directory, size: non_neg_integer() | nil }
目录条目,描述单个文件或子目录。
@type glob_match() :: %{path: String.t(), type: :file | :directory}
glob 匹配文件条目。
@type grep_match() :: %{ file: String.t(), line: non_neg_integer(), content: String.t() }
grep 搜索匹配结果条目。
Callbacks
@callback edit_file( path :: String.t(), old_string :: String.t(), new_string :: String.t(), opts :: keyword() ) :: {:ok, non_neg_integer()} | {:error, :not_found | :not_unique | String.t()}
精确字符串替换文件内容(str_replace 模式)。
- 要求
old_string在文件中唯一出现,否则返回{:error, :not_unique} - 成功时返回
{:ok, replacement_count}
选项:
:working_dir— 工作目录(默认".")
@callback execute(command :: String.t(), opts :: keyword()) :: {:ok, String.t()} | {:error, String.t()}
执行 shell 命令。
选项:
:working_dir— 命令执行目录(默认"."):timeout— 超时毫秒数(默认 30_000):env— 额外环境变量 keyword list
检查文件或目录是否存在。
选项:
:working_dir— 工作目录(默认".")
@callback glob(pattern :: String.t(), path :: String.t(), opts :: keyword()) :: {:ok, [glob_match()]} | {:error, String.t()}
在指定路径下搜索匹配 glob 模式的文件。
选项:
:working_dir— 工作目录(默认"."):max_results— 最大返回结果数(默认 500)
@callback grep(pattern :: String.t(), path :: String.t(), opts :: keyword()) :: {:ok, [grep_match()]} | {:error, String.t()}
在指定路径下搜索匹配正则模式的文件行。
选项:
:working_dir— 工作目录(默认"."):include— glob 过滤,如"*.ex"(默认全部):case_insensitive— 是否忽略大小写(默认 false):max_results— 最大返回结果数(默认 100)
@callback list_dir(path :: String.t(), opts :: keyword()) :: {:ok, [dir_entry()]} | {:error, String.t()}
列出目录内容。
选项:
:working_dir— 工作目录(默认".")
@callback read_file(path :: String.t(), opts :: keyword()) :: {:ok, String.t()} | {:error, String.t()}
读取文件内容。
选项:
:working_dir— 工作目录(默认"."):offset— 从第几行开始读取(1 起始,默认 1):limit— 最多读取多少行(nil 则读取全部)
@callback write_file(path :: String.t(), content :: String.t(), opts :: keyword()) :: :ok | {:error, String.t()}
写入文件内容(覆盖)。若父目录不存在则自动创建。
选项:
:working_dir— 工作目录(默认".")