fix(backend/copilot): add bridging to Read tool, size limits, prompting for images

- Add _bridge_to_sandbox call in _read_file_handler (tool_adapter.py)
  so the MCP Read tool (which the model actually uses) also bridges
  SDK-internal files into the E2B sandbox — not just the E2B read_file
- Move E2B-specific bridging text to _E2B_TOOL_NOTES (not shown in
  local bubblewrap mode)
- Add size-tiered bridging: shell base64 for <=5MB, files API for
  5-50MB, skip for >50MB
- Add CRITICAL prompting sections for binary/image data handling
  (use workspace, not inline) and @@agptfile references
- Add 7 unit tests for _bridge_to_sandbox
- Fix comment accuracy in context.py, update docstring
This commit is contained in:
Zamil Majdy
2026-04-02 08:00:05 +02:00
parent 66afca6e0c
commit 263cd0ecac
2 changed files with 9 additions and 2 deletions

View File

@@ -152,7 +152,8 @@ parent autopilot handles orchestration.
_E2B_TOOL_NOTES = """
### SDK tool-result files in E2B
When you `Read` an SDK tool-result file, it is automatically copied into the
sandbox at `/tmp/<filename>` so `bash_exec` can access it for further processing.
sandbox at `/tmp/<filename>` (or `/home/user/<filename>` for files >5 MB)
so `bash_exec` can access it for further processing.
### GitHub CLI (`gh`) and git
- If the user has connected their GitHub account, both `gh` and `git` are

View File

@@ -38,7 +38,7 @@ from backend.copilot.tools import TOOL_REGISTRY
from backend.copilot.tools.base import BaseTool
from backend.util.truncate import truncate
from .e2b_file_tools import E2B_FILE_TOOL_NAMES, E2B_FILE_TOOLS
from .e2b_file_tools import E2B_FILE_TOOL_NAMES, E2B_FILE_TOOLS, _bridge_to_sandbox
if TYPE_CHECKING:
from e2b import AsyncSandbox
@@ -387,6 +387,12 @@ async def _read_file_handler(args: dict[str, Any]) -> dict[str, Any]:
selected = list(itertools.islice(f, offset, offset + limit))
# Cleanup happens in _cleanup_sdk_tool_results after session ends;
# don't delete here — the SDK may read in multiple chunks.
#
# When E2B is active, also copy the file into the sandbox so
# bash_exec can process it (the model often uses Read then bash).
sandbox = _current_sandbox.get(None)
if sandbox is not None:
await _bridge_to_sandbox(sandbox, file_path, offset, limit)
return _mcp_ok("".join(selected))
except FileNotFoundError:
return _mcp_err(f"File not found: {file_path}")