Studio: correct the sandbox notes to match actual network and persistence
The sandbox note claimed the working directory starts empty, persists only for the conversation, and cannot reach any remote host. None of that holds: a project session reuses a shared sandbox that persists across its threads and may already contain files, and the code tools can reach an allowlist of public sites (github.com, huggingface.co, pypi.org). Reword the python/terminal note and the code-tool tip so the model lists the working directory and knows it can fetch from the allowlist, while still not assuming a mentioned path exists.
This commit is contained in:
parent
61523b73f1
commit
57a73f34d5
3 changed files with 70 additions and 15 deletions
|
|
@ -2953,16 +2953,19 @@ WEB_SEARCH_TOOL = {
|
|||
# nonexistent /mnt/data or cd/grep-ing a guessed local path for a repo the
|
||||
# user only mentioned but never uploaded.
|
||||
_SANDBOX_PATHS_NOTE = (
|
||||
" The working directory is an isolated scratch space that starts empty "
|
||||
"except for files created here or explicitly uploaded to this "
|
||||
"conversation, and it persists only for this conversation. This sandbox "
|
||||
"cannot reach other machines or remote hosts. A repository, folder, or "
|
||||
"file the user refers to is not present here unless it was uploaded or "
|
||||
"created in the sandbox, so do not assume a mentioned path exists or guess "
|
||||
"where it lives. Read and write files using relative paths in the working "
|
||||
"directory; absolute paths like /mnt/data or /tmp/outputs do not exist. If "
|
||||
"the files you need are not here, ask the user to upload them or provide an "
|
||||
"exact path instead of guessing one."
|
||||
" The working directory is an isolated scratch space that may already hold "
|
||||
"files from earlier work in this conversation or project, plus anything you "
|
||||
"create here or that is uploaded; it persists across this conversation and, "
|
||||
"for a project, across the project's threads. It can reach only a fixed "
|
||||
"allowlist of public sites (such as github.com, huggingface.co, and "
|
||||
"pypi.org), not the user's own machines, private hosts, or arbitrary "
|
||||
"addresses. A repository, folder, or file the user refers to is not present "
|
||||
"here unless it was uploaded, created here, or already part of this project, "
|
||||
"so list the working directory to see what is available rather than assuming "
|
||||
"a mentioned path exists or guessing where it lives. Read and write files "
|
||||
"using relative paths in the working directory; absolute paths like "
|
||||
"/mnt/data or /tmp/outputs do not exist. If the files you need are not here, "
|
||||
"ask the user to upload them or provide an exact path instead of guessing one."
|
||||
)
|
||||
|
||||
PYTHON_TOOL = {
|
||||
|
|
|
|||
|
|
@ -2405,11 +2405,13 @@ _TOOL_WEB_EXPANDED_TIP = (
|
|||
_TOOL_CODE_TIP = (
|
||||
"Use code execution for math, calculations, data processing, or to parse "
|
||||
"and analyze information from tool results. The python and terminal tools "
|
||||
"run in a sandbox whose working directory is an isolated scratch space and "
|
||||
"that cannot reach other machines or remote hosts, so do not assume a file, "
|
||||
"folder, or repository the user mentions is already present. If it has not "
|
||||
"been uploaded to this conversation, ask the user to upload it or give an "
|
||||
"exact path rather than running commands against a guessed one."
|
||||
"run in a sandbox whose working directory is an isolated scratch space that "
|
||||
"may already hold files from earlier work and can reach only a fixed "
|
||||
"allowlist of public sites, not the user's own machines or private hosts, so "
|
||||
"do not assume a file, folder, or repository the user mentions is already "
|
||||
"present. List the working directory to see what is there; if what you need "
|
||||
"is not present, ask the user to upload it or give an exact path rather than "
|
||||
"running commands against a guessed one."
|
||||
)
|
||||
_TOOL_ARTIFACT_TIP = (
|
||||
"For HTML, CSS, or JavaScript canvas requests, call render_html once when "
|
||||
|
|
|
|||
50
studio/backend/tests/test_sandbox_paths_note.py
Normal file
50
studio/backend/tests/test_sandbox_paths_note.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
"""Accuracy guards for the sandbox-paths note appended to the python/terminal
|
||||
tool descriptions (#7242).
|
||||
|
||||
The note must not misdirect the model with claims that are false for the real
|
||||
sandbox: (1) the sandbox is not network-isolated -- the python tool can reach an
|
||||
allowlist of public hosts (github.com / huggingface.co / pypi.org), so it must
|
||||
not claim it "cannot reach ... remote hosts" at all; (2) a project sandbox is a
|
||||
shared per-project directory, so a new thread can inherit files from prior
|
||||
threads -- the note must not claim the workdir "starts empty" or "persists only
|
||||
for this conversation".
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_BACKEND_DIR = str(Path(__file__).resolve().parent.parent)
|
||||
if _BACKEND_DIR not in sys.path:
|
||||
sys.path.insert(0, _BACKEND_DIR)
|
||||
|
||||
from core.inference.tools import PYTHON_TOOL, TERMINAL_TOOL, _SANDBOX_PATHS_NOTE
|
||||
|
||||
|
||||
def test_note_does_not_claim_full_network_isolation():
|
||||
lowered = _SANDBOX_PATHS_NOTE.lower()
|
||||
# The old absolute claim is false for the python tool (allowlisted egress).
|
||||
assert "cannot reach other machines or remote hosts" not in lowered
|
||||
# It should instead scope the block to private/arbitrary hosts and name the
|
||||
# allowlist so the model still fetches valid public URLs.
|
||||
assert "allowlist" in lowered
|
||||
assert "github.com" in lowered and "huggingface.co" in lowered
|
||||
assert "arbitrary" in lowered or "private" in lowered
|
||||
|
||||
|
||||
def test_note_does_not_claim_project_sandbox_starts_empty():
|
||||
lowered = _SANDBOX_PATHS_NOTE.lower()
|
||||
# Project sandboxes are shared across threads, so these are inaccurate.
|
||||
assert "starts empty" not in lowered
|
||||
assert "persists only for this conversation" not in lowered
|
||||
# It should acknowledge that project files may already be present.
|
||||
assert "project" in lowered
|
||||
|
||||
|
||||
def test_note_is_appended_to_both_tool_descriptions():
|
||||
assert PYTHON_TOOL["function"]["description"].endswith(_SANDBOX_PATHS_NOTE)
|
||||
assert TERMINAL_TOOL["function"]["description"].endswith(_SANDBOX_PATHS_NOTE)
|
||||
Loading…
Add table
Add a link
Reference in a new issue