Local-реализация
Protocol сам по себе не читает файлы. Нужен скучный бэкенд —
тот же subprocess, что был в модуле 2, только спрятан
за Sandbox. Скучный — хорошо: это база, с которой
сравнивают memory и cloud.
ЧТО ПОЛУЧИТСЯ
sandbox_local.py с create_local_sandbox(dir).
Агент снова запускается и ведёт себя как в модуле 3 — но plumbing
другой.
Слова, которые встретятся
-
Local sandbox — команды на вашем диске, в вашей
рабочей папке. Изоляции нет:
rm -rfвсё ещё возможен (если approval пропустит). -
Фабрика —
create_local_sandboxвозвращает объект, который удовлетворяетSandbox.
Быстрый путь
- Создать
sandbox_local.py. - В
main.py:sandbox = create_local_sandbox(cwd),agent.run(..., deps=sandbox). - Прогнать знакомые промпты — результат как раньше.
Какие файлы трогаем
| Файл | Что делать |
|---|---|
sandbox_local.py |
Создать. create_local_sandbox — read_file + exec + stop. |
main.py |
Править. Создать sandbox, передать в tools и в deps=. |
local_bash.py |
Можно удалить или оставить — логику exec переносим в sandbox_local. |
prompts.py |
sandbox_type: sandbox.type (обычно "local"). |
Шаг 1. Реализация
sandbox_local.py
import subprocess
from dataclasses import dataclass
from pathlib import Path
from sandbox import ExecResult
@dataclass
class LocalSandbox:
type: str
working_directory: str
_root: Path
async def read_file(self, path: str) -> str:
return (self._root / path).read_text(encoding="utf-8")
async def exec(self, command: str) -> ExecResult:
try:
proc = subprocess.run(
command,
shell=True,
cwd=self._root,
capture_output=True,
text=True,
timeout=30,
)
out = (proc.stdout or "") + (proc.stderr or "")
return {"stdout": out.strip(), "exit_code": proc.returncode}
except subprocess.TimeoutExpired:
return {"stdout": "Таймаут: больше 30 секунд.", "exit_code": 124}
async def stop(self) -> None:
pass # локально нечего убирать
def create_local_sandbox(directory: Path) -> LocalSandbox:
root = directory.resolve()
return LocalSandbox(
type="local",
working_directory=str(root),
_root=root,
)
exec не бросает исключение на ненулевой exit code —
tools ждут объект с stdout и кодом. Как в модуле 2.
Шаг 2. Подключить в main.py
from sandbox_local import create_local_sandbox
sandbox = create_local_sandbox(cwd)
needs_approval = create_approval({"mode": "interactive"})
bash_fn = create_bash_tool(sandbox, needs_approval)
instructions = build_system_prompt({
"working_directory": sandbox.working_directory,
"sandbox_type": sandbox.type,
"tool_names": tool_names,
...
})
async def main() -> None:
result = await agent.run(prompt, deps=sandbox)
print(result.output)
await sandbox.stop()
На время отладки: print(f"Sandbox: {sandbox.type}") —
должно быть local.
ЕСЛИ ПОВЕДЕНИЕ ИЗМЕНИЛОСЬ
На тех же промптах ответ должен совпадать с модулем 3.
Ищите tool, который всё ещё лезет в
Path / subprocess
мимо sandbox.
Проверьте
uv run python main.py . "Прочитай main.py, первые 5 строк"
uv run python main.py . "Найди TODO в *.py"
uv run python main.py . "Выполни: ls -la"
В stderr (если добавили print): Sandbox: local.
Tools работают, approval на опасных командах — как в модуле 2.
Готово, если:
sandbox_local.pyэкспортируетcreate_local_sandbox- Агент запускается с
deps=sandbox read/grep/bashработают как в модуле 3sandbox.type == "local"попадает в промпт