Shell Built-In
内建 shell tools、sandbox 模式与审批流程
Shell Built-In
Shell 不再是 plugin。它是 @downcity/shell 提供的内建能力,通过 new Shell() 挂到 Agent 上。
import { Agent } from "@downcity/agent";
import { Shell } from "@downcity/shell";
const agent = new Agent({
id: "repo-helper",
path: "/path/to/project",
shell: new Shell(),
});Tools
传入 shell: new Shell() 后,模型会获得这些工具:
shell_execshell_session
shell_exec 用于一次性非交互命令;shell_session 用于 PTY 交互式会话,支持 start、send、read、list、stop action。
shell_exec 的 timeout_ms 是命令总执行时长。显式传入较短值会按该值超时并终止进程;长任务应改用 shell_session,不要依赖 shell_exec 持续等待。
Sandbox 模式
Shell tools 默认进入 Safe Sandbox。
只有需要宿主级能力时才使用 sandbox: "unrestricted",例如 brew install、npm install -g、pip install --user、gh auth login,或初始化项目 sandbox 外的宿主服务。
shell_exec({
cmd: "brew install ffmpeg",
sandbox: "unrestricted",
reason: "Homebrew 需要写入宿主级 package 目录。",
});Unrestricted 执行每次都需要用户审批。缺少 reason 会在执行前被拒绝。
审批 API
前端或 SDK 客户端通过发起工具调用的 Session 审批:
const pending = await session.approvals();
await session.resolve_approval({
approval_id: pending[0].approval_id,
decision: "approved",
});本地和远程 Session 暴露相同 API。实时 UI 在 session.subscribe() 收到 approval-required Tool Part 时,从 mutation.part.approval 读取请求,再通过 session.resolve_approval(...) 提交决定。
Session Approval Mode
Shell approval mode 只作用于当前 session:
ask:默认模式,每次 unrestricted 请求都进入审批队列。always-allow:当前 session 内自动通过 shell approval,不再弹出新的 pending approval。
await session.set_approval_mode({
mode: "always-allow",
});
const current = await session.approval_mode();always-allow 不改变 sandbox 模式,只是把原本需要手动批准的 unrestricted 请求自动记录为 approved。已有 pending approval 不会被自动批准。
关键语义
- Shell 归属于
@downcity/shell,不属于@downcity/plugins。 - Agent 只挂载 Shell tools;工具审批和实时 Mutation 都归属具体 Session。
- Safe Sandbox 命令可读写项目,并使用配置的 sandbox 目录。
- Unrestricted 命令只有在逐次审批通过后才会离开 Safe Sandbox 执行。
always-allow只影响当前 session 的新 approval 请求,不影响其它 session。- 对 unrestricted
shell_session会话执行的每一次send也需要审批。 agent.dispose()会释放 Shell sessions,并把仍在等待的 approval 兑现为过期,调用不会永久挂起。