mirror of
https://github.com/langgenius/dify.git
synced 2026-10-04 13:47:55 +08:00
fix(agent): preserve sandbox file errors in stdout 🤖🤖🤖 (#42624)
This commit is contained in:
1 parent
3e787d11cc
commit
d2c2e39ba7
2 files changed
+30
-3
No files matched your search
@@ -50,6 +50,10 @@ import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
# The shell transport may expose stdout only. Keep Python errors in the same
|
||||
# stream so the server can classify unavailable paths instead of returning 502.
|
||||
sys.stderr = sys.stdout
|
||||
|
||||
path = sys.argv[1]
|
||||
response_path = sys.argv[2]
|
||||
limit = int(sys.argv[3])
|
||||
@@ -89,6 +93,8 @@ import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
sys.stderr = sys.stdout
|
||||
|
||||
path = sys.argv[1]
|
||||
response_path = sys.argv[2]
|
||||
max_bytes = int(sys.argv[3])
|
||||
|
||||
@@ -117,6 +117,8 @@ class _ProviderErrorCommands(_Commands):
|
||||
|
||||
@dataclass(slots=True)
|
||||
class _LocalCommands(_Commands):
|
||||
capture_stderr: bool = True
|
||||
|
||||
async def run(
|
||||
self,
|
||||
script: str,
|
||||
@@ -133,7 +135,7 @@ class _LocalCommands(_Commands):
|
||||
cwd=cwd,
|
||||
env={**os.environ, **(env or {})},
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.STDOUT,
|
||||
stderr=asyncio.subprocess.STDOUT if self.capture_stderr else asyncio.subprocess.DEVNULL,
|
||||
)
|
||||
output, _ = await asyncio.wait_for(process.communicate(), timeout=timeout)
|
||||
text = output.decode(errors="replace")
|
||||
@@ -195,12 +197,16 @@ def _service(
|
||||
return service, backend
|
||||
|
||||
|
||||
def _local_service(tmp_path: Path) -> tuple[BindingFileService, _Backend, _LocalCommands, Path, Path]:
|
||||
def _local_service(
|
||||
tmp_path: Path,
|
||||
*,
|
||||
capture_stderr: bool = True,
|
||||
) -> tuple[BindingFileService, _Backend, _LocalCommands, Path, Path]:
|
||||
workspace = tmp_path / "workspace"
|
||||
home = tmp_path / "home"
|
||||
workspace.mkdir()
|
||||
home.mkdir()
|
||||
commands = _LocalCommands(outputs=[])
|
||||
commands = _LocalCommands(outputs=[], capture_stderr=capture_stderr)
|
||||
backend = _Backend(
|
||||
lease=cast(
|
||||
RuntimeLease,
|
||||
@@ -412,6 +418,21 @@ async def test_browse_preserves_binding_file_error_and_releases_lease(operation:
|
||||
assert backend.releases == 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize("operation", ["list", "read"])
|
||||
@pytest.mark.anyio
|
||||
async def test_missing_path_is_classified_when_transport_only_captures_stdout(tmp_path: Path, operation: str) -> None:
|
||||
service, backend, commands, _, _ = _local_service(tmp_path, capture_stderr=False)
|
||||
with pytest.raises(BindingFileError) as error:
|
||||
if operation == "list":
|
||||
await service.list_files(BindingFileListRequest(backend_binding_ref="binding-ref", path="missing"))
|
||||
else:
|
||||
await service.read_file(BindingFileReadRequest(backend_binding_ref="binding-ref", path="missing"))
|
||||
assert error.value.code == "invalid_binding_path"
|
||||
assert error.value.status_code == 400
|
||||
assert backend.releases == 1
|
||||
assert commands.deletes == ["local-job-1"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("operation", ["list", "read"])
|
||||
@pytest.mark.anyio
|
||||
async def test_browse_maps_malformed_backend_response_to_unavailable_and_releases_lease(operation: str) -> None:
|
||||
|
||||
Reference in new issue
Block a user