mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-04-25 11:18:22 +00:00
fix(sandbox): improve sandbox security and preserve multimodal content (#2114)
* fix: improve sandbox security and preserve multimodal content * Add unit test modifications for test_injects_uploaded_files_tag_into_list_content * format updated_content * Add regression tests for multimodal upload content and host bash default safety
This commit is contained in:
parent
024ac0e464
commit
02569136df
@ -262,21 +262,25 @@ class UploadsMiddleware(AgentMiddleware[UploadsMiddlewareState]):
|
||||
files_message = self._create_files_message(new_files, historical_files)
|
||||
|
||||
# Extract original content - handle both string and list formats
|
||||
original_content = ""
|
||||
if isinstance(last_message.content, str):
|
||||
original_content = last_message.content
|
||||
elif isinstance(last_message.content, list):
|
||||
text_parts = []
|
||||
for block in last_message.content:
|
||||
if isinstance(block, dict) and block.get("type") == "text":
|
||||
text_parts.append(block.get("text", ""))
|
||||
original_content = "\n".join(text_parts)
|
||||
original_content = last_message.content
|
||||
if isinstance(original_content, str):
|
||||
# Simple case: string content, just prepend files message
|
||||
updated_content = f"{files_message}\n\n{original_content}"
|
||||
elif isinstance(original_content, list):
|
||||
# Complex case: list content (multimodal), preserve all blocks
|
||||
# Prepend files message as the first text block
|
||||
files_block = {"type": "text", "text": f"{files_message}\n\n"}
|
||||
# Keep all original blocks (including images)
|
||||
updated_content = [files_block, *original_content]
|
||||
else:
|
||||
# Other types, preserve as-is
|
||||
updated_content = original_content
|
||||
|
||||
# Create new message with combined content.
|
||||
# Preserve additional_kwargs (including files metadata) so the frontend
|
||||
# can read structured file info from the streamed message.
|
||||
updated_message = HumanMessage(
|
||||
content=f"{files_message}\n\n{original_content}",
|
||||
content=updated_content,
|
||||
id=last_message.id,
|
||||
additional_kwargs=last_message.additional_kwargs,
|
||||
)
|
||||
|
||||
@ -39,7 +39,7 @@ def is_host_bash_allowed(config=None) -> bool:
|
||||
|
||||
sandbox_cfg = getattr(config, "sandbox", None)
|
||||
if sandbox_cfg is None:
|
||||
return True
|
||||
return False
|
||||
if not uses_local_sandbox_provider(config):
|
||||
return True
|
||||
return bool(getattr(sandbox_cfg, "allow_host_bash", False))
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from deerflow.sandbox.security import is_host_bash_allowed
|
||||
from deerflow.tools.tools import get_available_tools
|
||||
|
||||
|
||||
@ -79,3 +80,8 @@ def test_get_available_tools_keeps_bash_for_aio_sandbox(monkeypatch):
|
||||
|
||||
assert "bash" in names
|
||||
assert "ls" in names
|
||||
|
||||
|
||||
def test_is_host_bash_allowed_defaults_false_when_sandbox_missing():
|
||||
assert is_host_bash_allowed(SimpleNamespace()) is False
|
||||
assert is_host_bash_allowed(SimpleNamespace(sandbox=None)) is False
|
||||
|
||||
@ -256,8 +256,10 @@ class TestBeforeAgent:
|
||||
|
||||
assert result is not None
|
||||
updated_msg = result["messages"][-1]
|
||||
assert "<uploaded_files>" in updated_msg.content
|
||||
assert "analyse this" in updated_msg.content
|
||||
assert isinstance(updated_msg.content, list)
|
||||
combined_text = "\n".join(block.get("text", "") for block in updated_msg.content if isinstance(block, dict))
|
||||
assert "<uploaded_files>" in combined_text
|
||||
assert "analyse this" in combined_text
|
||||
|
||||
def test_preserves_additional_kwargs_on_updated_message(self, tmp_path):
|
||||
mw = _middleware(tmp_path)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user