Vendored deer-flow upstream (bytedance/deer-flow) plus prompt-injection hardening: - New deerflow.security package: content_delimiter, html_cleaner, sanitizer (8 layers — invisible chars, control chars, symbols, NFC, PUA, tag chars, horizontal whitespace collapse with newline/tab preservation, length cap) - New deerflow.community.searx package: web_search, web_fetch, image_search backed by a private SearX instance, every external string sanitized and wrapped in <<<EXTERNAL_UNTRUSTED_CONTENT>>> delimiters - All native community web providers (ddg_search, tavily, exa, firecrawl, jina_ai, infoquest, image_search) replaced with hard-fail stubs that raise NativeWebToolDisabledError at import time, so a misconfigured tool.use path fails loud rather than silently falling back to unsanitized output - Native client back-doors (jina_client.py, infoquest_client.py) stubbed too - Native-tool tests quarantined under tests/_disabled_native/ (collect_ignore_glob via local conftest.py) - Sanitizer Layer 7 fix: only collapse horizontal whitespace, preserve newlines and tabs so list/table structure survives - Hardened runtime config.yaml references only the searx-backed tools - Factory overlay (backend/) kept in sync with deer-flow tree as a reference / source See HARDENING.md for the full audit trail and verification steps.
91 lines
2.7 KiB
Python
91 lines
2.7 KiB
Python
"""Tests for automatic thread title generation."""
|
|
|
|
import pytest
|
|
|
|
from deerflow.agents.middlewares.title_middleware import TitleMiddleware
|
|
from deerflow.config.title_config import TitleConfig, get_title_config, set_title_config
|
|
|
|
|
|
class TestTitleConfig:
|
|
"""Tests for TitleConfig."""
|
|
|
|
def test_default_config(self):
|
|
"""Test default configuration values."""
|
|
config = TitleConfig()
|
|
assert config.enabled is True
|
|
assert config.max_words == 6
|
|
assert config.max_chars == 60
|
|
assert config.model_name is None
|
|
|
|
def test_custom_config(self):
|
|
"""Test custom configuration."""
|
|
config = TitleConfig(
|
|
enabled=False,
|
|
max_words=10,
|
|
max_chars=100,
|
|
model_name="gpt-4",
|
|
)
|
|
assert config.enabled is False
|
|
assert config.max_words == 10
|
|
assert config.max_chars == 100
|
|
assert config.model_name == "gpt-4"
|
|
|
|
def test_config_validation(self):
|
|
"""Test configuration validation."""
|
|
# max_words should be between 1 and 20
|
|
with pytest.raises(ValueError):
|
|
TitleConfig(max_words=0)
|
|
with pytest.raises(ValueError):
|
|
TitleConfig(max_words=21)
|
|
|
|
# max_chars should be between 10 and 200
|
|
with pytest.raises(ValueError):
|
|
TitleConfig(max_chars=5)
|
|
with pytest.raises(ValueError):
|
|
TitleConfig(max_chars=201)
|
|
|
|
def test_get_set_config(self):
|
|
"""Test global config getter and setter."""
|
|
original_config = get_title_config()
|
|
|
|
# Set new config
|
|
new_config = TitleConfig(enabled=False, max_words=10)
|
|
set_title_config(new_config)
|
|
|
|
# Verify it was set
|
|
assert get_title_config().enabled is False
|
|
assert get_title_config().max_words == 10
|
|
|
|
# Restore original config
|
|
set_title_config(original_config)
|
|
|
|
|
|
class TestTitleMiddleware:
|
|
"""Tests for TitleMiddleware."""
|
|
|
|
def test_middleware_initialization(self):
|
|
"""Test middleware can be initialized."""
|
|
middleware = TitleMiddleware()
|
|
assert middleware is not None
|
|
assert middleware.state_schema is not None
|
|
|
|
# TODO: Add integration tests with mock Runtime
|
|
# def test_should_generate_title(self):
|
|
# """Test title generation trigger logic."""
|
|
# pass
|
|
|
|
# def test_generate_title(self):
|
|
# """Test title generation."""
|
|
# pass
|
|
|
|
# def test_after_agent_hook(self):
|
|
# """Test after_agent hook."""
|
|
# pass
|
|
|
|
|
|
# TODO: Add integration tests
|
|
# - Test with real LangGraph runtime
|
|
# - Test title persistence with checkpointer
|
|
# - Test fallback behavior when LLM fails
|
|
# - Test concurrent title generation
|