mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-19 19:16:17 +00:00
* feat(knowledge): integrate RAGFlow retrieval and management * test(knowledge): cover merged listing tool * feat(knowledge): add per-message retrieval scope * chore(docs): remove unrelated document * docs(knowledge): add interaction screenshots * feat(knowledge): simplify scope selector trigger * docs(knowledge): refresh selector screenshot * feat(knowledge): defer standalone management * docs(knowledge): show chat-only scope UI * fix(knowledge): honor scope on clarification replies * fix(knowledge): harden scoped replay validation * docs(knowledge): clarify replay scope precedence * fix(knowledge): keep provider settings on tools * fix(config): preserve tools-only knowledge settings * fix(knowledge): submit custom assistant identity * refactor(knowledge): trim PR scope changes * fix(knowledge): sanitize document scope display * feat(knowledge): enable scope selection in main chat * fix(knowledge): emphasize active scope icon without button frame * fix(knowledge): close context scrubbing and refresh e2e checks * fix(knowledge): preserve idempotent canonical retries * fix(knowledge): accept promptless conversation runs * style(knowledge): format backend regression tests * chore(knowledge): trim PR scope and fix frontend format * fix(knowledge): remove shared-scope notice * fix(knowledge): remove scope persistence notice * docs(knowledge): include main chat in catalog scope * fix(knowledge): preserve scope recovery and upgrades * fix(config): preserve LightRAG knowledge upgrades --------- Co-authored-by: foreleven <for-eleven@hotmail.com>
240 lines
7.3 KiB
Python
240 lines
7.3 KiB
Python
import json
|
|
|
|
import pytest
|
|
from pydantic import ValidationError
|
|
|
|
from deerflow.knowledge_scope import (
|
|
KNOWLEDGE_SCOPE_KEY,
|
|
KnowledgeScope,
|
|
canonicalize_knowledge_scope,
|
|
execution_scope,
|
|
)
|
|
|
|
|
|
def test_all_and_disabled_canonicalize_without_selection_fields() -> None:
|
|
assert canonicalize_knowledge_scope({"version": 1, "mode": "all"}) == {
|
|
"version": 1,
|
|
"mode": "all",
|
|
}
|
|
assert canonicalize_knowledge_scope({"version": 1, "mode": "disabled"}) == {
|
|
"version": 1,
|
|
"mode": "disabled",
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"payload",
|
|
[
|
|
{"version": 2, "mode": "all"},
|
|
{"version": 1, "mode": "all", "future": True},
|
|
{"version": 1, "mode": "all", "dataset_ids": ["dataset-a"]},
|
|
{"version": 1, "mode": "disabled", "display": {"datasets": []}},
|
|
{"version": 1, "mode": "selected", "dataset_ids": []},
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"document_filters": [{"dataset_id": "dataset-a", "document_ids": []}],
|
|
},
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"document_filters": [
|
|
{"dataset_id": "dataset-a", "document_ids": ["doc-a"]},
|
|
{"dataset_id": "dataset-a", "document_ids": ["doc-b"]},
|
|
],
|
|
},
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"document_filters": [{"dataset_id": "dataset-b", "document_ids": ["doc-a"]}],
|
|
},
|
|
],
|
|
)
|
|
def test_invalid_scope_shapes_are_rejected(payload: dict) -> None:
|
|
with pytest.raises(ValidationError):
|
|
canonicalize_knowledge_scope(payload)
|
|
|
|
|
|
def test_selected_scope_trims_and_stably_deduplicates_ids() -> None:
|
|
scope = canonicalize_knowledge_scope(
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": [" dataset-a ", "dataset-b", "dataset-a"],
|
|
"document_filters": [
|
|
{
|
|
"dataset_id": " dataset-b ",
|
|
"document_ids": [" doc-1 ", "doc-2", "doc-1"],
|
|
}
|
|
],
|
|
}
|
|
)
|
|
|
|
assert scope == {
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a", "dataset-b"],
|
|
"document_filters": [{"dataset_id": "dataset-b", "document_ids": ["doc-1", "doc-2"]}],
|
|
}
|
|
|
|
|
|
def test_execution_scope_drops_untrusted_display_snapshot() -> None:
|
|
scope = canonicalize_knowledge_scope(
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"display": {"datasets": [{"id": "dataset-a", "name": "Agriculture", "documents": []}]},
|
|
}
|
|
)
|
|
|
|
assert execution_scope(scope) == {
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
}
|
|
assert KNOWLEDGE_SCOPE_KEY == "knowledge_scope"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"payload",
|
|
[
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"display": {"datasets": [{"id": "dataset-b", "name": "Other"}]},
|
|
},
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"document_filters": [{"dataset_id": "dataset-a", "document_ids": ["doc-a"]}],
|
|
"display": {
|
|
"datasets": [
|
|
{
|
|
"id": "dataset-a",
|
|
"name": "Agriculture",
|
|
"documents": [{"id": "doc-b", "name": "Other.pdf"}],
|
|
}
|
|
]
|
|
},
|
|
},
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"display": {
|
|
"datasets": [
|
|
{"id": "dataset-a", "name": "First"},
|
|
{"id": "dataset-a", "name": "Duplicate"},
|
|
]
|
|
},
|
|
},
|
|
],
|
|
)
|
|
def test_display_must_be_unique_and_related_to_execution_selection(payload: dict) -> None:
|
|
with pytest.raises(ValidationError):
|
|
canonicalize_knowledge_scope(payload)
|
|
|
|
|
|
def test_scope_capacity_limits_are_rejected_without_truncation() -> None:
|
|
with pytest.raises(ValidationError):
|
|
canonicalize_knowledge_scope(
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": [f"dataset-{index}" for index in range(101)],
|
|
}
|
|
)
|
|
|
|
with pytest.raises(ValidationError):
|
|
canonicalize_knowledge_scope(
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"document_filters": [
|
|
{
|
|
"dataset_id": "dataset-a",
|
|
"document_ids": [f"doc-{index}" for index in range(1001)],
|
|
}
|
|
],
|
|
}
|
|
)
|
|
|
|
with pytest.raises(ValidationError):
|
|
canonicalize_knowledge_scope(
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["x" * 257],
|
|
}
|
|
)
|
|
|
|
|
|
def test_display_capacity_and_canonical_json_byte_limit_are_enforced() -> None:
|
|
with pytest.raises(ValidationError):
|
|
canonicalize_knowledge_scope(
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": [f"dataset-{index}" for index in range(21)],
|
|
"display": {"datasets": [{"id": f"dataset-{index}", "name": f"Dataset {index}"} for index in range(21)]},
|
|
}
|
|
)
|
|
|
|
oversized = {
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"document_filters": [
|
|
{
|
|
"dataset_id": "dataset-a",
|
|
"document_ids": [f"doc-{index}-{'x' * 240}" for index in range(300)],
|
|
}
|
|
],
|
|
}
|
|
assert len(json.dumps(oversized, ensure_ascii=False).encode()) > 64 * 1024
|
|
with pytest.raises(ValidationError):
|
|
canonicalize_knowledge_scope(oversized)
|
|
|
|
|
|
def test_model_rejects_more_than_fifty_display_documents_and_long_names() -> None:
|
|
document_ids = [f"doc-{index}" for index in range(51)]
|
|
with pytest.raises(ValidationError):
|
|
KnowledgeScope.model_validate(
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"document_filters": [{"dataset_id": "dataset-a", "document_ids": document_ids}],
|
|
"display": {
|
|
"datasets": [
|
|
{
|
|
"id": "dataset-a",
|
|
"name": "Agriculture",
|
|
"documents": [{"id": document_id, "name": f"Document {index}"} for index, document_id in enumerate(document_ids)],
|
|
}
|
|
]
|
|
},
|
|
}
|
|
)
|
|
|
|
with pytest.raises(ValidationError):
|
|
canonicalize_knowledge_scope(
|
|
{
|
|
"version": 1,
|
|
"mode": "selected",
|
|
"dataset_ids": ["dataset-a"],
|
|
"display": {
|
|
"datasets": [
|
|
{"id": "dataset-a", "name": "名" * 257},
|
|
]
|
|
},
|
|
}
|
|
)
|