mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-23 08:56:42 +08:00
### What problem does this PR solve?
This reverts commit 1a608ac411.
### Type of change
- [x] Other (please describe):
This commit is contained in:
@@ -216,24 +216,12 @@ def list_chat_assistants(auth, params=None):
|
||||
return res.json()
|
||||
|
||||
|
||||
def get_chat_assistant(auth, chat_assistant_id):
|
||||
url = f"{HOST_ADDRESS}{CHAT_ASSISTANT_API_URL}/{chat_assistant_id}"
|
||||
res = requests.get(url=url, headers=HEADERS, auth=auth)
|
||||
return res.json()
|
||||
|
||||
|
||||
def update_chat_assistant(auth, chat_assistant_id, payload=None):
|
||||
url = f"{HOST_ADDRESS}{CHAT_ASSISTANT_API_URL}/{chat_assistant_id}"
|
||||
res = requests.put(url=url, headers=HEADERS, auth=auth, json=payload)
|
||||
return res.json()
|
||||
|
||||
|
||||
def patch_chat_assistant(auth, chat_assistant_id, payload=None):
|
||||
url = f"{HOST_ADDRESS}{CHAT_ASSISTANT_API_URL}/{chat_assistant_id}"
|
||||
res = requests.patch(url=url, headers=HEADERS, auth=auth, json=payload)
|
||||
return res.json()
|
||||
|
||||
|
||||
def delete_chat_assistants(auth, payload=None):
|
||||
url = f"{HOST_ADDRESS}{CHAT_ASSISTANT_API_URL}"
|
||||
res = requests.delete(url=url, headers=HEADERS, auth=auth, json=payload)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
import pytest
|
||||
from common import batch_create_chat_assistants, delete_all_chat_assistants, get_chat_assistant, list_documents, parse_documents
|
||||
from common import batch_create_chat_assistants, delete_all_chat_assistants, list_chat_assistants, list_documents, parse_documents
|
||||
from utils import wait_for
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ def add_chat_assistants_func(request, HttpApiAuth, add_document):
|
||||
@pytest.fixture(scope="function")
|
||||
def chat_assistant_llm_model_type(HttpApiAuth, add_chat_assistants_func):
|
||||
_, _, chat_assistant_ids = add_chat_assistants_func
|
||||
res = get_chat_assistant(HttpApiAuth, chat_assistant_ids[0])
|
||||
res = list_chat_assistants(HttpApiAuth, {"id": chat_assistant_ids[0]})
|
||||
if res.get("code") == 0 and res.get("data"):
|
||||
return res["data"].get("llm_setting", {}).get("model_type", "chat")
|
||||
return res["data"][0].get("llm", {}).get("model_type", "chat")
|
||||
return "chat"
|
||||
|
||||
@@ -44,40 +44,38 @@ class _AwaitableValue:
|
||||
|
||||
|
||||
class _DummyKB:
|
||||
def __init__(self, kid="kb-1", embd_id="embd@factory", chunk_num=1, name="Dataset A", status="1"):
|
||||
self.id = kid
|
||||
def __init__(self, embd_id="embd@factory", chunk_num=1, tenant_embd_id=1):
|
||||
self.embd_id = embd_id
|
||||
self.chunk_num = chunk_num
|
||||
self.name = name
|
||||
self.status = status
|
||||
self.tenant_embd_id = tenant_embd_id
|
||||
|
||||
def to_json(self):
|
||||
return {"id": "kb-1"}
|
||||
|
||||
|
||||
class _DummyDialogRecord:
|
||||
def __init__(self, data=None):
|
||||
self._data = data or {
|
||||
def __init__(self):
|
||||
self._data = {
|
||||
"id": "chat-1",
|
||||
"name": "chat-name",
|
||||
"description": "desc",
|
||||
"icon": "icon.png",
|
||||
"kb_ids": ["kb-1"],
|
||||
"llm_id": "glm-4",
|
||||
"llm_setting": {"temperature": 0.1},
|
||||
"prompt_config": {
|
||||
"system": "Answer with {knowledge}",
|
||||
"parameters": [{"key": "knowledge", "optional": False}],
|
||||
"prologue": "hello",
|
||||
"quote": True,
|
||||
},
|
||||
"llm_setting": {"temperature": 0.1},
|
||||
"llm_id": "glm-4",
|
||||
"similarity_threshold": 0.2,
|
||||
"vector_similarity_weight": 0.3,
|
||||
"top_n": 6,
|
||||
"top_k": 1024,
|
||||
"rerank_id": "",
|
||||
"meta_data_filter": {},
|
||||
"tenant_id": "tenant-1",
|
||||
"top_k": 1024,
|
||||
"kb_ids": ["kb-1"],
|
||||
"icon": "icon.png",
|
||||
}
|
||||
|
||||
def to_dict(self):
|
||||
def to_json(self):
|
||||
return deepcopy(self._data)
|
||||
|
||||
|
||||
@@ -87,15 +85,47 @@ def _run(coro):
|
||||
|
||||
def _load_chat_module(monkeypatch):
|
||||
repo_root = Path(__file__).resolve().parents[4]
|
||||
module_name = "test_chat_restful_routes_unit_module"
|
||||
module_path = repo_root / "api" / "apps" / "restful_apis" / "chat_api.py"
|
||||
|
||||
common_pkg = ModuleType("common")
|
||||
common_pkg.__path__ = [str(repo_root / "common")]
|
||||
monkeypatch.setitem(sys.modules, "common", common_pkg)
|
||||
|
||||
deepdoc_pkg = ModuleType("deepdoc")
|
||||
deepdoc_parser_pkg = ModuleType("deepdoc.parser")
|
||||
deepdoc_parser_pkg.__path__ = []
|
||||
|
||||
class _StubPdfParser:
|
||||
pass
|
||||
|
||||
class _StubExcelParser:
|
||||
pass
|
||||
|
||||
class _StubDocxParser:
|
||||
pass
|
||||
|
||||
deepdoc_parser_pkg.PdfParser = _StubPdfParser
|
||||
deepdoc_parser_pkg.ExcelParser = _StubExcelParser
|
||||
deepdoc_parser_pkg.DocxParser = _StubDocxParser
|
||||
deepdoc_pkg.parser = deepdoc_parser_pkg
|
||||
monkeypatch.setitem(sys.modules, "deepdoc", deepdoc_pkg)
|
||||
monkeypatch.setitem(sys.modules, "deepdoc.parser", deepdoc_parser_pkg)
|
||||
|
||||
deepdoc_excel_module = ModuleType("deepdoc.parser.excel_parser")
|
||||
deepdoc_excel_module.RAGFlowExcelParser = _StubExcelParser
|
||||
monkeypatch.setitem(sys.modules, "deepdoc.parser.excel_parser", deepdoc_excel_module)
|
||||
|
||||
deepdoc_parser_utils = ModuleType("deepdoc.parser.utils")
|
||||
deepdoc_parser_utils.get_text = lambda *_args, **_kwargs: ""
|
||||
monkeypatch.setitem(sys.modules, "deepdoc.parser.utils", deepdoc_parser_utils)
|
||||
monkeypatch.setitem(sys.modules, "xgboost", ModuleType("xgboost"))
|
||||
|
||||
module_name = "test_chat_sdk_routes_unit_module"
|
||||
module_path = repo_root / "api" / "apps" / "sdk" / "chat.py"
|
||||
spec = importlib.util.spec_from_file_location(module_name, module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
module.manager = _DummyManager()
|
||||
monkeypatch.setitem(sys.modules, module_name, module)
|
||||
spec.loader.exec_module(module)
|
||||
monkeypatch.setattr(module, "current_user", SimpleNamespace(id="tenant-1"))
|
||||
return module
|
||||
|
||||
|
||||
@@ -104,357 +134,227 @@ def _set_request_json(monkeypatch, module, payload):
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_create_chat_uses_direct_chat_fields(monkeypatch):
|
||||
def test_create_internal_failure_paths(monkeypatch):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
saved = {}
|
||||
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{
|
||||
"name": "chat-a",
|
||||
"icon": "icon.png",
|
||||
"dataset_ids": ["kb-1"],
|
||||
"llm_id": "glm-4",
|
||||
"llm_setting": {"temperature": 0.8},
|
||||
"prompt_config": {
|
||||
"system": "Answer with {knowledge}",
|
||||
"parameters": [{"key": "knowledge", "optional": False}],
|
||||
"prologue": "Hi",
|
||||
},
|
||||
"vector_similarity_weight": 0.25,
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(llm_id="glm-4")))
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "accessible", lambda **_kwargs: [SimpleNamespace(id="kb-1")])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "query", lambda **_kwargs: [_DummyKB()])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "get_by_id", lambda _id: (True, _DummyKB()))
|
||||
_set_request_json(monkeypatch, module, {"name": "chat-a", "dataset_ids": ["kb-1", "kb-2"]})
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "accessible", lambda **_kwargs: [SimpleNamespace(id="kb")])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "query", lambda **_kwargs: [_DummyKB(chunk_num=1)])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "get_by_ids", lambda _ids: [_DummyKB(embd_id="embd-a@x"), _DummyKB(embd_id="embd-b@y")])
|
||||
monkeypatch.setattr(module.TenantLLMService, "split_model_name_and_factory", lambda model: (model.split("@")[0], "factory"))
|
||||
monkeypatch.setattr(module.TenantLLMService, "query", lambda **_kwargs: [SimpleNamespace(id="llm-1")])
|
||||
res = _run(module.create.__wrapped__("tenant-1"))
|
||||
assert res["code"] == module.RetCode.AUTHENTICATION_ERROR
|
||||
assert "different embedding models" in res["message"]
|
||||
|
||||
def _save(**kwargs):
|
||||
saved.update(kwargs)
|
||||
return True
|
||||
_set_request_json(monkeypatch, module, {"name": "chat-a", "dataset_ids": []})
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (False, None))
|
||||
res = _run(module.create.__wrapped__("tenant-1"))
|
||||
assert res["message"] == "Tenant not found!"
|
||||
|
||||
monkeypatch.setattr(module.DialogService, "save", _save)
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord(saved)))
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(llm_id="glm-4")))
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [])
|
||||
monkeypatch.setattr(module.DialogService, "save", lambda **_kwargs: False)
|
||||
res = _run(module.create.__wrapped__("tenant-1"))
|
||||
assert res["message"] == "Fail to new a chat!"
|
||||
|
||||
res = _run(module.create.__wrapped__())
|
||||
|
||||
assert res["code"] == 0
|
||||
assert saved["kb_ids"] == ["kb-1"]
|
||||
assert saved["prompt_config"]["prologue"] == "Hi"
|
||||
assert saved["llm_id"] == "glm-4"
|
||||
assert saved["llm_setting"]["temperature"] == 0.8
|
||||
assert res["data"]["dataset_ids"] == ["kb-1"]
|
||||
assert res["data"]["kb_names"] == ["Dataset A"]
|
||||
assert "kb_ids" not in res["data"]
|
||||
assert "prompt" not in res["data"]
|
||||
assert "llm" not in res["data"]
|
||||
assert "avatar" not in res["data"]
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
def test_create_chat_accepts_provider_scoped_rerank_id(monkeypatch):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
saved = {}
|
||||
query_calls = []
|
||||
monkeypatch.setattr(module.DialogService, "save", lambda **_kwargs: True)
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (False, None))
|
||||
res = _run(module.create.__wrapped__("tenant-1"))
|
||||
assert res["message"] == "Fail to new a chat!"
|
||||
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{
|
||||
"name": "chat-a",
|
||||
"icon": "icon.png",
|
||||
"dataset_ids": ["kb-1"],
|
||||
"llm_id": "glm-4@ZHIPU-AI",
|
||||
"llm_setting": {"temperature": 0.8},
|
||||
"prompt_config": {
|
||||
"system": "Answer with {knowledge}",
|
||||
"parameters": [{"key": "knowledge", "optional": False}],
|
||||
"prologue": "Hi",
|
||||
},
|
||||
"rerank_id": "custom-reranker@OpenAI",
|
||||
"vector_similarity_weight": 0.25,
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(llm_id="glm-4@ZHIPU-AI")))
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "accessible", lambda **_kwargs: [SimpleNamespace(id="kb-1")])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "query", lambda **_kwargs: [_DummyKB()])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "get_by_id", lambda _id: (True, _DummyKB()))
|
||||
|
||||
def _split_model_name_and_factory(model_name):
|
||||
return {
|
||||
"glm-4@ZHIPU-AI": ("glm-4", "ZHIPU-AI"),
|
||||
"custom-reranker@OpenAI": ("custom-reranker", "OpenAI"),
|
||||
}.get(model_name, (model_name, None))
|
||||
|
||||
def _query(**kwargs):
|
||||
query_calls.append(kwargs)
|
||||
if kwargs == {
|
||||
"tenant_id": "tenant-1",
|
||||
"llm_name": "glm-4",
|
||||
"llm_factory": "ZHIPU-AI",
|
||||
"model_type": "chat",
|
||||
}:
|
||||
return [SimpleNamespace(id="llm-1")]
|
||||
if kwargs == {
|
||||
"tenant_id": "tenant-1",
|
||||
"llm_name": "custom-reranker",
|
||||
"llm_factory": "OpenAI",
|
||||
"model_type": "rerank",
|
||||
}:
|
||||
return [SimpleNamespace(id="rerank-1")]
|
||||
return []
|
||||
|
||||
monkeypatch.setattr(module.TenantLLMService, "split_model_name_and_factory", _split_model_name_and_factory)
|
||||
monkeypatch.setattr(module.TenantLLMService, "query", _query)
|
||||
|
||||
def _save(**kwargs):
|
||||
saved.update(kwargs)
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(module.DialogService, "save", _save)
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord(saved)))
|
||||
|
||||
res = _run(module.create.__wrapped__())
|
||||
|
||||
assert res["code"] == 0
|
||||
assert saved["rerank_id"] == "custom-reranker@OpenAI"
|
||||
assert {
|
||||
"tenant_id": "tenant-1",
|
||||
"llm_name": "custom-reranker",
|
||||
"llm_factory": "OpenAI",
|
||||
"model_type": "rerank",
|
||||
} in query_calls
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
def test_create_chat_allows_default_knowledge_placeholder_without_sources(monkeypatch):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
saved = {}
|
||||
|
||||
_set_request_json(monkeypatch, module, {"name": "chat-a"})
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(llm_id="glm-4")))
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [])
|
||||
monkeypatch.setattr(module.TenantLLMService, "get_api_key", lambda *_args, **_kwargs: SimpleNamespace(id=1))
|
||||
|
||||
def _save(**kwargs):
|
||||
saved.update(kwargs)
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(module.DialogService, "save", _save)
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord(saved)))
|
||||
|
||||
res = _run(module.create.__wrapped__())
|
||||
|
||||
assert res["code"] == 0
|
||||
assert saved["kb_ids"] == []
|
||||
assert saved["prompt_config"]["system"].find("{knowledge}") >= 0
|
||||
assert saved["prompt_config"]["parameters"] == [{"key": "knowledge", "optional": False}]
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
def test_create_chat_uses_tenant_default_llm_when_llm_id_is_null(monkeypatch):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
saved = {}
|
||||
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{
|
||||
"name": "chat-a",
|
||||
"dataset_ids": ["kb-1"],
|
||||
"llm_id": None,
|
||||
"llm_setting": {"temperature": 0.8},
|
||||
"prompt_config": {
|
||||
"system": "Answer with {knowledge}",
|
||||
"parameters": [{"key": "knowledge", "optional": False}],
|
||||
},
|
||||
},
|
||||
{"name": "chat-rerank", "dataset_ids": [], "prompt": {"rerank_model": "unknown-rerank-model"}},
|
||||
)
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(llm_id="glm-4")))
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "accessible", lambda **_kwargs: [SimpleNamespace(id="kb-1")])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "query", lambda **_kwargs: [_DummyKB()])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "get_by_id", lambda _id: (True, _DummyKB()))
|
||||
monkeypatch.setattr(module.TenantLLMService, "get_api_key", lambda *_args, **_kwargs: SimpleNamespace(id=1))
|
||||
rerank_query_calls = []
|
||||
|
||||
def _save(**kwargs):
|
||||
saved.update(kwargs)
|
||||
return True
|
||||
def _mock_tenant_llm_query(**kwargs):
|
||||
rerank_query_calls.append(kwargs)
|
||||
return False
|
||||
|
||||
monkeypatch.setattr(module.DialogService, "save", _save)
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord(saved)))
|
||||
monkeypatch.setattr(module.TenantLLMService, "query", _mock_tenant_llm_query)
|
||||
res = _run(module.create.__wrapped__("tenant-1"))
|
||||
assert "`rerank_model` unknown-rerank-model doesn't exist" in res["message"]
|
||||
assert rerank_query_calls[-1]["model_type"] == "rerank"
|
||||
assert rerank_query_calls[-1]["llm_name"] == "unknown-rerank-model"
|
||||
|
||||
res = _run(module.create.__wrapped__())
|
||||
|
||||
assert res["code"] == 0
|
||||
assert saved["llm_id"] == "glm-4"
|
||||
assert saved["llm_setting"]["temperature"] == 0.8
|
||||
_set_request_json(monkeypatch, module, {"name": "chat-tenant", "dataset_ids": [], "tenant_id": "tenant-forbidden"})
|
||||
res = _run(module.create.__wrapped__("tenant-1"))
|
||||
assert res["message"] == "`tenant_id` must not be provided."
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_patch_chat_merges_prompt_and_llm_settings(monkeypatch):
|
||||
def test_update_internal_failure_paths(monkeypatch):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
updated = {}
|
||||
existing = _DummyDialogRecord().to_dict()
|
||||
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{
|
||||
"prompt_config": {"prologue": "updated opener"},
|
||||
"llm_setting": {"temperature": 0.9},
|
||||
},
|
||||
)
|
||||
_set_request_json(monkeypatch, module, {"name": "anything"})
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [])
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["message"] == "You do not own the chat"
|
||||
|
||||
_set_request_json(monkeypatch, module, {"name": "chat-name"})
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [SimpleNamespace(id="chat-1")])
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord(existing)))
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(llm_id="glm-4")))
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (False, None))
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["message"] == "Tenant not found!"
|
||||
|
||||
def _update(_chat_id, payload):
|
||||
updated.update(payload)
|
||||
return True
|
||||
_set_request_json(monkeypatch, module, {"dataset_ids": ["kb-1", "kb-2"]})
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(id="tenant-1")))
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "accessible", lambda **_kwargs: [SimpleNamespace(id="kb")])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "query", lambda **_kwargs: [_DummyKB(chunk_num=1)])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "get_by_ids", lambda _ids: [_DummyKB(embd_id="embd-a@x"), _DummyKB(embd_id="embd-b@y")])
|
||||
monkeypatch.setattr(module.TenantLLMService, "split_model_name_and_factory", lambda model: (model.split("@")[0], "factory"))
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["code"] == module.RetCode.AUTHENTICATION_ERROR
|
||||
assert "different embedding models" in res["message"]
|
||||
|
||||
monkeypatch.setattr(module.DialogService, "update_by_id", _update)
|
||||
_set_request_json(monkeypatch, module, {"avatar": "new-avatar"})
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord()))
|
||||
monkeypatch.setattr(module.DialogService, "update_by_id", lambda *_args, **_kwargs: False)
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["message"] == "Chat not found!"
|
||||
|
||||
res = _run(module.patch_chat.__wrapped__("chat-1"))
|
||||
|
||||
assert res["code"] == 0
|
||||
assert updated["prompt_config"]["system"] == "Answer with {knowledge}"
|
||||
assert updated["prompt_config"]["prologue"] == "updated opener"
|
||||
assert updated["llm_setting"]["temperature"] == 0.9
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_patch_chat_drops_response_only_fields_before_update(monkeypatch):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
updated = {}
|
||||
existing = _DummyDialogRecord().to_dict()
|
||||
payload = {
|
||||
"name": "renamed-chat",
|
||||
"description": existing["description"],
|
||||
"icon": existing["icon"],
|
||||
"dataset_ids": existing["kb_ids"],
|
||||
"kb_names": ["Dataset A"],
|
||||
"llm_id": existing["llm_id"],
|
||||
"llm_setting": existing["llm_setting"],
|
||||
"prompt_config": existing["prompt_config"],
|
||||
"similarity_threshold": existing["similarity_threshold"],
|
||||
"vector_similarity_weight": existing["vector_similarity_weight"],
|
||||
"top_n": existing["top_n"],
|
||||
"top_k": existing["top_k"],
|
||||
"rerank_id": existing["rerank_id"],
|
||||
}
|
||||
|
||||
_set_request_json(monkeypatch, module, payload)
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(id="tenant-1")))
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord()))
|
||||
monkeypatch.setattr(module.DialogService, "update_by_id", lambda *_args, **_kwargs: True)
|
||||
monkeypatch.setattr(
|
||||
module.DialogService,
|
||||
"query",
|
||||
lambda **kwargs: [] if "name" in kwargs else [SimpleNamespace(id="chat-1")],
|
||||
lambda **kwargs: (
|
||||
[SimpleNamespace(id="chat-1")]
|
||||
if kwargs.get("id") == "chat-1"
|
||||
else ([SimpleNamespace(id="dup")] if kwargs.get("name") == "dup-name" else [])
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
module.TenantLLMService,
|
||||
"split_model_name_and_factory",
|
||||
lambda model: (model.split("@")[0], "factory"),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
module.TenantLLMService,
|
||||
"query",
|
||||
lambda **kwargs: kwargs.get("llm_name") in {"glm-4", "allowed-rerank"},
|
||||
)
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord(existing)))
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(llm_id="glm-4")))
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "accessible", lambda **_kwargs: [SimpleNamespace(id="kb-1")])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "query", lambda **_kwargs: [_DummyKB()])
|
||||
monkeypatch.setattr(module.TenantLLMService, "split_model_name_and_factory", lambda model: (model.split("@")[0], "factory"))
|
||||
monkeypatch.setattr(module.TenantLLMService, "query", lambda **_kwargs: [SimpleNamespace(id="llm-1")])
|
||||
|
||||
def _update(_chat_id, req):
|
||||
updated.update(req)
|
||||
return True
|
||||
|
||||
monkeypatch.setattr(module.DialogService, "update_by_id", _update)
|
||||
|
||||
res = _run(module.patch_chat.__wrapped__("chat-1"))
|
||||
|
||||
_set_request_json(monkeypatch, module, {"show_quotation": True})
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["code"] == 0
|
||||
assert updated["name"] == "renamed-chat"
|
||||
assert "kb_names" not in updated
|
||||
|
||||
_set_request_json(monkeypatch, module, {"dataset_ids": ["kb-no-owner"]})
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "accessible", lambda **_kwargs: [])
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert "You don't own the dataset kb-no-owner" in res["message"]
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_update_chat_rejects_knowledge_placeholder_without_sources(monkeypatch):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
existing = _DummyDialogRecord().to_dict()
|
||||
_set_request_json(monkeypatch, module, {"dataset_ids": ["kb-unparsed"]})
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "accessible", lambda **_kwargs: [SimpleNamespace(id="kb-unparsed")])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "query", lambda **_kwargs: [_DummyKB(chunk_num=0)])
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert "doesn't own parsed file" in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"llm": {"model_name": "unknown-model", "model_type": "unsupported"}})
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert "`model_name` unknown-model doesn't exist" in res["message"]
|
||||
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{
|
||||
"name": "chat-name",
|
||||
"description": "desc",
|
||||
"icon": "icon.png",
|
||||
"dataset_ids": [],
|
||||
"llm_id": "glm-4",
|
||||
"llm_setting": {"temperature": 0.1},
|
||||
"prompt_config": {
|
||||
"system": "Answer with {knowledge}",
|
||||
"parameters": [{"key": "knowledge", "optional": False}],
|
||||
"prologue": "hello",
|
||||
"quote": True,
|
||||
},
|
||||
"similarity_threshold": 0.2,
|
||||
"vector_similarity_weight": 0.3,
|
||||
"top_n": 6,
|
||||
"top_k": 1024,
|
||||
"rerank_id": "",
|
||||
},
|
||||
{"prompt": {"prompt": "No placeholder", "variables": [{"key": "knowledge", "optional": False}], "rerank_model": "unknown-rerank"}},
|
||||
)
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [SimpleNamespace(id="chat-1")])
|
||||
monkeypatch.setattr(module.DialogService, "get_by_id", lambda _id: (True, _DummyDialogRecord(existing)))
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tid: (True, SimpleNamespace(llm_id="glm-4")))
|
||||
monkeypatch.setattr(module.TenantLLMService, "split_model_name_and_factory", lambda model: (model.split("@")[0], "factory"))
|
||||
monkeypatch.setattr(module.TenantLLMService, "query", lambda **_kwargs: [SimpleNamespace(id="llm-1")])
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert "`rerank_model` unknown-rerank doesn't exist" in res["message"]
|
||||
|
||||
res = _run(module.update_chat.__wrapped__("chat-1"))
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{"prompt": {"prompt": "No placeholder", "variables": [{"key": "knowledge", "optional": False}]}},
|
||||
)
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert "Parameter 'knowledge' is not used" in res["message"]
|
||||
|
||||
assert res["code"] == 102
|
||||
assert res["message"] == "Please remove `{knowledge}` in system prompt since no dataset / Tavily used here."
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{"prompt": {"prompt": "Optional-only prompt", "variables": [{"key": "maybe", "optional": True}]}},
|
||||
)
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["code"] == 0
|
||||
|
||||
_set_request_json(monkeypatch, module, {"name": ""})
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["message"] == "`name` cannot be empty."
|
||||
|
||||
_set_request_json(monkeypatch, module, {"name": "dup-name"})
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["message"] == "Duplicated chat name in updating chat."
|
||||
|
||||
_set_request_json(monkeypatch, module, {"llm": {"model_name": "glm-4", "temperature": 0.9}})
|
||||
res = _run(module.update.__wrapped__("tenant-1", "chat-1"))
|
||||
assert res["code"] == 0
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_list_chats_returns_old_business_fields(monkeypatch):
|
||||
def test_delete_duplicate_no_success_path(monkeypatch):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
monkeypatch.setattr(
|
||||
module,
|
||||
"request",
|
||||
SimpleNamespace(
|
||||
args=SimpleNamespace(
|
||||
get=lambda key, default=None: {
|
||||
"keywords": "",
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"orderby": "create_time",
|
||||
"desc": "true",
|
||||
}.get(key, default),
|
||||
getlist=lambda _key: [],
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
_set_request_json(monkeypatch, module, {})
|
||||
monkeypatch.setattr(
|
||||
module.DialogService,
|
||||
"get_by_tenant_ids",
|
||||
lambda *_args, **_kwargs: (
|
||||
[_DummyDialogRecord().to_dict()],
|
||||
1,
|
||||
),
|
||||
"query",
|
||||
lambda **_kwargs: (_ for _ in ()).throw(AssertionError("query must not run for empty delete payload")),
|
||||
)
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "get_by_id", lambda _id: (True, _DummyKB()))
|
||||
res = _run(module.delete_chats.__wrapped__("tenant-1"))
|
||||
assert res["code"] == module.RetCode.SUCCESS
|
||||
|
||||
res = module.list_chats.__wrapped__()
|
||||
_set_request_json(monkeypatch, module, {"ids": ["chat-1", "chat-1"]})
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [SimpleNamespace(id="chat-1")])
|
||||
monkeypatch.setattr(module.DialogService, "update_by_id", lambda *_args, **_kwargs: 0)
|
||||
res = _run(module.delete_chats.__wrapped__("tenant-1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "Duplicate assistant ids: chat-1" in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"ids": ["missing-chat"]})
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [])
|
||||
res = _run(module.delete_chats.__wrapped__("tenant-1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "Assistant(missing-chat) not found." in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"ids": ["chat-1", "chat-1"]})
|
||||
monkeypatch.setattr(module.DialogService, "query", lambda **_kwargs: [SimpleNamespace(id="chat-1")])
|
||||
monkeypatch.setattr(module.DialogService, "update_by_id", lambda *_args, **_kwargs: 1)
|
||||
res = _run(module.delete_chats.__wrapped__("tenant-1"))
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["success_count"] == 1
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_list_missing_kb_warning_and_desc_false(monkeypatch, caplog):
|
||||
module = _load_chat_module(monkeypatch)
|
||||
|
||||
monkeypatch.setattr(module, "request", SimpleNamespace(args={"desc": "False"}))
|
||||
monkeypatch.setattr(module.DialogService, "get_list", lambda *_args, **_kwargs: [
|
||||
{
|
||||
"id": "chat-1",
|
||||
"name": "chat-name",
|
||||
"prompt_config": {"system": "Answer with {knowledge}", "parameters": [{"key": "knowledge", "optional": False}], "do_refer": True},
|
||||
"similarity_threshold": 0.2,
|
||||
"vector_similarity_weight": 0.3,
|
||||
"top_n": 6,
|
||||
"rerank_id": "",
|
||||
"llm_setting": {"temperature": 0.1},
|
||||
"llm_id": "glm-4",
|
||||
"kb_ids": ["missing-kb"],
|
||||
"icon": "icon.png",
|
||||
}
|
||||
])
|
||||
monkeypatch.setattr(module.KnowledgebaseService, "query", lambda **_kwargs: [])
|
||||
|
||||
with caplog.at_level("WARNING"):
|
||||
res = module.list_chat.__wrapped__("tenant-1")
|
||||
|
||||
assert res["code"] == 0
|
||||
chat = res["data"]["chats"][0]
|
||||
assert chat["icon"] == "icon.png"
|
||||
assert chat["dataset_ids"] == ["kb-1"]
|
||||
assert chat["kb_names"] == ["Dataset A"]
|
||||
assert "kb_ids" not in chat
|
||||
assert chat["prompt_config"]["prologue"] == "hello"
|
||||
assert "dataset_names" not in chat
|
||||
assert "prompt" not in chat
|
||||
assert "llm" not in chat
|
||||
|
||||
|
||||
assert res["data"][0]["datasets"] == []
|
||||
assert res["data"][0]["avatar"] == "icon.png"
|
||||
assert "does not exist" in caplog.text
|
||||
|
||||
@@ -63,7 +63,7 @@ class TestChatAssistantsDelete:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
res = list_chat_assistants(HttpApiAuth)
|
||||
assert len(res["data"]["chats"]) == remaining
|
||||
assert len(res["data"]) == remaining
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"payload",
|
||||
@@ -83,7 +83,7 @@ class TestChatAssistantsDelete:
|
||||
assert res["data"]["success_count"] == 5
|
||||
|
||||
res = list_chat_assistants(HttpApiAuth)
|
||||
assert len(res["data"]["chats"]) == 0
|
||||
assert len(res["data"]) == 0
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_repeated_deletion(self, HttpApiAuth, add_chat_assistants_func):
|
||||
@@ -124,7 +124,7 @@ class TestChatAssistantsDelete:
|
||||
assert res["code"] == 0
|
||||
|
||||
res = list_chat_assistants(HttpApiAuth)
|
||||
assert len(res["data"]["chats"]) == 0
|
||||
assert len(res["data"]) == 0
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_delete_all_errors_no_success_p2(self, HttpApiAuth, add_chat_assistants_func):
|
||||
|
||||
@@ -16,16 +16,12 @@
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
import pytest
|
||||
from common import delete_datasets, get_chat_assistant, list_chat_assistants
|
||||
from common import delete_datasets, list_chat_assistants
|
||||
from configs import INVALID_API_TOKEN
|
||||
from libs.auth import RAGFlowHttpApiAuth
|
||||
from utils import is_sorted
|
||||
|
||||
|
||||
def _chat_list(res):
|
||||
return res["data"]["chats"]
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
class TestAuthorization:
|
||||
@pytest.mark.parametrize(
|
||||
@@ -51,8 +47,7 @@ class TestChatAssistantsList:
|
||||
def test_default(self, HttpApiAuth):
|
||||
res = list_chat_assistants(HttpApiAuth)
|
||||
assert res["code"] == 0
|
||||
assert len(_chat_list(res)) == 5
|
||||
assert res["data"]["total"] == 5
|
||||
assert len(res["data"]) == 5
|
||||
|
||||
@pytest.mark.p1
|
||||
@pytest.mark.parametrize(
|
||||
@@ -83,7 +78,7 @@ class TestChatAssistantsList:
|
||||
res = list_chat_assistants(HttpApiAuth, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
assert len(_chat_list(res)) == expected_page_size
|
||||
assert len(res["data"]) == expected_page_size
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@@ -123,7 +118,7 @@ class TestChatAssistantsList:
|
||||
res = list_chat_assistants(HttpApiAuth, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
assert len(_chat_list(res)) == expected_page_size
|
||||
assert len(res["data"]) == expected_page_size
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@@ -131,13 +126,13 @@ class TestChatAssistantsList:
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected_code, assertions, expected_message",
|
||||
[
|
||||
({"orderby": None}, 0, lambda r: is_sorted(_chat_list(r), "create_time", True), ""),
|
||||
({"orderby": "create_time"}, 0, lambda r: is_sorted(_chat_list(r), "create_time", True), ""),
|
||||
({"orderby": "update_time"}, 0, lambda r: is_sorted(_chat_list(r), "update_time", True), ""),
|
||||
({"orderby": None}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"orderby": "create_time"}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"orderby": "update_time"}, 0, lambda r: (is_sorted(r["data"], "update_time", True)), ""),
|
||||
pytest.param(
|
||||
{"orderby": "name", "desc": "False"},
|
||||
0,
|
||||
lambda r: is_sorted(_chat_list(r), "name", False),
|
||||
lambda r: (is_sorted(r["data"], "name", False)),
|
||||
"",
|
||||
marks=pytest.mark.skip(reason="issues/5851"),
|
||||
),
|
||||
@@ -170,14 +165,14 @@ class TestChatAssistantsList:
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected_code, assertions, expected_message",
|
||||
[
|
||||
({"desc": None}, 0, lambda r: is_sorted(_chat_list(r), "create_time", True), ""),
|
||||
({"desc": "true"}, 0, lambda r: is_sorted(_chat_list(r), "create_time", True), ""),
|
||||
({"desc": "True"}, 0, lambda r: is_sorted(_chat_list(r), "create_time", True), ""),
|
||||
({"desc": True}, 0, lambda r: is_sorted(_chat_list(r), "create_time", True), ""),
|
||||
({"desc": "false"}, 0, lambda r: is_sorted(_chat_list(r), "create_time", False), ""),
|
||||
({"desc": "False"}, 0, lambda r: is_sorted(_chat_list(r), "create_time", False), ""),
|
||||
({"desc": False}, 0, lambda r: is_sorted(_chat_list(r), "create_time", False), ""),
|
||||
({"desc": "False", "orderby": "update_time"}, 0, lambda r: is_sorted(_chat_list(r), "update_time", False), ""),
|
||||
({"desc": None}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"desc": "true"}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"desc": "True"}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"desc": True}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"desc": "false"}, 0, lambda r: (is_sorted(r["data"], "create_time", False)), ""),
|
||||
({"desc": "False"}, 0, lambda r: (is_sorted(r["data"], "create_time", False)), ""),
|
||||
({"desc": False}, 0, lambda r: (is_sorted(r["data"], "create_time", False)), ""),
|
||||
({"desc": "False", "orderby": "update_time"}, 0, lambda r: (is_sorted(r["data"], "update_time", False)), ""),
|
||||
pytest.param(
|
||||
{"desc": "unknown"},
|
||||
102,
|
||||
@@ -207,81 +202,90 @@ class TestChatAssistantsList:
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected_code, expected_num, expected_message",
|
||||
[
|
||||
({"keywords": None}, 0, 5, ""),
|
||||
({"keywords": ""}, 0, 5, ""),
|
||||
({"keywords": "test_chat_assistant_1"}, 0, 1, ""),
|
||||
({"keywords": "unknown"}, 0, 0, ""),
|
||||
({"name": None}, 0, 5, ""),
|
||||
({"name": ""}, 0, 5, ""),
|
||||
({"name": "test_chat_assistant_1"}, 0, 1, ""),
|
||||
({"name": "unknown"}, 102, 0, "The chat doesn't exist"),
|
||||
],
|
||||
)
|
||||
def test_keywords(self, HttpApiAuth, params, expected_code, expected_num, expected_message):
|
||||
def test_name(self, HttpApiAuth, params, expected_code, expected_num, expected_message):
|
||||
res = list_chat_assistants(HttpApiAuth, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
if params["keywords"] in [None, ""]:
|
||||
assert len(_chat_list(res)) == expected_num
|
||||
if params["name"] in [None, ""]:
|
||||
assert len(res["data"]) == expected_num
|
||||
else:
|
||||
assert len(_chat_list(res)) == expected_num
|
||||
if expected_num:
|
||||
assert _chat_list(res)[0]["name"] == params["keywords"]
|
||||
assert res["data"][0]["name"] == params["name"]
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p1
|
||||
@pytest.mark.parametrize(
|
||||
"chat_assistant_id, expected_code, expected_message",
|
||||
"chat_assistant_id, expected_code, expected_num, expected_message",
|
||||
[
|
||||
(lambda r: r[0], 0, ""),
|
||||
("unknown", 401, "No authorization."),
|
||||
(None, 0, 5, ""),
|
||||
("", 0, 5, ""),
|
||||
(lambda r: r[0], 0, 1, ""),
|
||||
("unknown", 102, 0, "The chat doesn't exist"),
|
||||
],
|
||||
)
|
||||
def test_get_chat_assistant(
|
||||
def test_id(
|
||||
self,
|
||||
HttpApiAuth,
|
||||
add_chat_assistants,
|
||||
chat_assistant_id,
|
||||
expected_code,
|
||||
expected_message,
|
||||
):
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
chat_id = chat_assistant_id(chat_assistant_ids) if callable(chat_assistant_id) else chat_assistant_id
|
||||
res = get_chat_assistant(HttpApiAuth, chat_id)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
assert res["data"]["id"] == chat_id
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"chat_assistant_id, keywords, expected_code, expected_num, expected_message",
|
||||
[
|
||||
(lambda r: r[0], "test_chat_assistant_0", 0, 1, ""),
|
||||
(lambda r: r[0], "test_chat_assistant_1", 0, 0, ""),
|
||||
(lambda r: r[0], "unknown", 0, 0, ""),
|
||||
],
|
||||
)
|
||||
def test_get_and_keywords_are_separate_lookups(
|
||||
self,
|
||||
HttpApiAuth,
|
||||
add_chat_assistants,
|
||||
chat_assistant_id,
|
||||
keywords,
|
||||
expected_code,
|
||||
expected_num,
|
||||
expected_message,
|
||||
):
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
chat_id = chat_assistant_id(chat_assistant_ids) if callable(chat_assistant_id) else chat_assistant_id
|
||||
|
||||
get_res = get_chat_assistant(HttpApiAuth, chat_id)
|
||||
list_res = list_chat_assistants(HttpApiAuth, params={"keywords": keywords})
|
||||
|
||||
assert get_res["code"] == expected_code
|
||||
assert list_res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
assert len(_chat_list(list_res)) == expected_num
|
||||
if callable(chat_assistant_id):
|
||||
params = {"id": chat_assistant_id(chat_assistant_ids)}
|
||||
else:
|
||||
assert get_res["message"] == expected_message
|
||||
params = {"id": chat_assistant_id}
|
||||
|
||||
res = list_chat_assistants(HttpApiAuth, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
if params["id"] in [None, ""]:
|
||||
assert len(res["data"]) == expected_num
|
||||
else:
|
||||
assert res["data"][0]["id"] == params["id"]
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"chat_assistant_id, name, expected_code, expected_num, expected_message",
|
||||
[
|
||||
(lambda r: r[0], "test_chat_assistant_0", 0, 1, ""),
|
||||
(lambda r: r[0], "test_chat_assistant_1", 102, 0, "The chat doesn't exist"),
|
||||
(lambda r: r[0], "unknown", 102, 0, "The chat doesn't exist"),
|
||||
("id", "chat_assistant_0", 102, 0, "The chat doesn't exist"),
|
||||
],
|
||||
)
|
||||
def test_name_and_id(
|
||||
self,
|
||||
HttpApiAuth,
|
||||
add_chat_assistants,
|
||||
chat_assistant_id,
|
||||
name,
|
||||
expected_code,
|
||||
expected_num,
|
||||
expected_message,
|
||||
):
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
if callable(chat_assistant_id):
|
||||
params = {"id": chat_assistant_id(chat_assistant_ids), "name": name}
|
||||
else:
|
||||
params = {"id": chat_assistant_id, "name": name}
|
||||
|
||||
res = list_chat_assistants(HttpApiAuth, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
assert len(res["data"]) == expected_num
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_concurrent_list(self, HttpApiAuth):
|
||||
@@ -297,7 +301,7 @@ class TestChatAssistantsList:
|
||||
params = {"a": "b"}
|
||||
res = list_chat_assistants(HttpApiAuth, params=params)
|
||||
assert res["code"] == 0
|
||||
assert len(_chat_list(res)) == 5
|
||||
assert len(res["data"]) == 5
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_list_chats_after_deleting_associated_dataset(self, HttpApiAuth, add_chat_assistants):
|
||||
@@ -307,10 +311,10 @@ class TestChatAssistantsList:
|
||||
|
||||
res = list_chat_assistants(HttpApiAuth)
|
||||
assert res["code"] == 0
|
||||
assert len(_chat_list(res)) == 5
|
||||
assert len(res["data"]) == 5
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_desc_false_parse_branch_p2(self, HttpApiAuth):
|
||||
res = list_chat_assistants(HttpApiAuth, params={"desc": "False", "orderby": "create_time"})
|
||||
assert res["code"] == 0
|
||||
assert is_sorted(_chat_list(res), "create_time", False)
|
||||
assert is_sorted(res["data"], "create_time", False)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
import pytest
|
||||
from common import create_chat_assistant, get_chat_assistant, patch_chat_assistant, update_chat_assistant
|
||||
from common import create_chat_assistant, list_chat_assistants, update_chat_assistant
|
||||
from configs import CHAT_ASSISTANT_NAME_LIMIT, INVALID_API_TOKEN
|
||||
from libs.auth import RAGFlowHttpApiAuth
|
||||
from utils import encode_avatar
|
||||
@@ -48,18 +48,18 @@ class TestChatAssistantUpdate:
|
||||
pytest.param({"name": "a" * (CHAT_ASSISTANT_NAME_LIMIT + 1)}, 102, "", marks=pytest.mark.skip(reason="issues/")),
|
||||
pytest.param({"name": 1}, 100, "", marks=pytest.mark.skip(reason="issues/")),
|
||||
pytest.param({"name": ""}, 102, "`name` cannot be empty.", marks=pytest.mark.p3),
|
||||
pytest.param({"name": "test_chat_assistant_1"}, 102, "Duplicated chat name.", marks=pytest.mark.p3),
|
||||
pytest.param({"name": "TEST_CHAT_ASSISTANT_1"}, 102, "Duplicated chat name.", marks=pytest.mark.p3),
|
||||
pytest.param({"name": "test_chat_assistant_1"}, 102, "Duplicated chat name in updating chat.", marks=pytest.mark.p3),
|
||||
pytest.param({"name": "TEST_CHAT_ASSISTANT_1"}, 102, "Duplicated chat name in updating chat.", marks=pytest.mark.p3),
|
||||
],
|
||||
)
|
||||
def test_name(self, HttpApiAuth, add_chat_assistants_func, payload, expected_code, expected_message):
|
||||
_, _, chat_assistant_ids = add_chat_assistants_func
|
||||
|
||||
res = patch_chat_assistant(HttpApiAuth, chat_assistant_ids[0], payload)
|
||||
res = update_chat_assistant(HttpApiAuth, chat_assistant_ids[0], payload)
|
||||
assert res["code"] == expected_code, res
|
||||
if expected_code == 0:
|
||||
res = get_chat_assistant(HttpApiAuth, chat_assistant_ids[0])
|
||||
assert res["data"]["name"] == payload.get("name")
|
||||
res = list_chat_assistants(HttpApiAuth, {"id": chat_assistant_ids[0]})
|
||||
assert res["data"][0]["name"] == payload.get("name")
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@@ -69,7 +69,7 @@ class TestChatAssistantUpdate:
|
||||
pytest.param([], 0, "", marks=pytest.mark.skip(reason="issues/")),
|
||||
pytest.param(lambda r: [r], 0, "", marks=pytest.mark.p1),
|
||||
pytest.param(["invalid_dataset_id"], 102, "You don't own the dataset invalid_dataset_id", marks=pytest.mark.p3),
|
||||
pytest.param("invalid_dataset_id", 102, "`dataset_ids` should be a list.", marks=pytest.mark.p3),
|
||||
pytest.param("invalid_dataset_id", 102, "You don't own the dataset i", marks=pytest.mark.p3),
|
||||
],
|
||||
)
|
||||
def test_dataset_ids(self, HttpApiAuth, add_chat_assistants_func, dataset_ids, expected_code, expected_message):
|
||||
@@ -83,8 +83,8 @@ class TestChatAssistantUpdate:
|
||||
res = update_chat_assistant(HttpApiAuth, chat_assistant_ids[0], payload)
|
||||
assert res["code"] == expected_code, res
|
||||
if expected_code == 0:
|
||||
res = get_chat_assistant(HttpApiAuth, chat_assistant_ids[0])
|
||||
assert res["data"]["name"] == payload.get("name")
|
||||
res = list_chat_assistants(HttpApiAuth, {"id": chat_assistant_ids[0]})
|
||||
assert res["data"][0]["name"] == payload.get("name")
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@@ -92,7 +92,7 @@ class TestChatAssistantUpdate:
|
||||
def test_avatar(self, HttpApiAuth, add_chat_assistants_func, tmp_path):
|
||||
dataset_id, _, chat_assistant_ids = add_chat_assistants_func
|
||||
fn = create_image_file(tmp_path / "ragflow_test.png")
|
||||
payload = {"name": "avatar_test", "icon": encode_avatar(fn), "dataset_ids": [dataset_id]}
|
||||
payload = {"name": "avatar_test", "avatar": encode_avatar(fn), "dataset_ids": [dataset_id]}
|
||||
res = update_chat_assistant(HttpApiAuth, chat_assistant_ids[0], payload)
|
||||
assert res["code"] == 0
|
||||
|
||||
@@ -101,8 +101,8 @@ class TestChatAssistantUpdate:
|
||||
"llm, expected_code, expected_message",
|
||||
[
|
||||
({}, 0, ""),
|
||||
({"llm_id": "glm-4"}, 0, ""),
|
||||
({"llm_id": "unknown"}, 102, "`llm_id` unknown doesn't exist"),
|
||||
({"model_name": "glm-4"}, 0, ""),
|
||||
({"model_name": "unknown"}, 102, "`model_name` unknown doesn't exist"),
|
||||
({"temperature": 0}, 0, ""),
|
||||
({"temperature": 1}, 0, ""),
|
||||
pytest.param({"temperature": -1}, 0, "", marks=pytest.mark.skip),
|
||||
@@ -133,23 +133,23 @@ class TestChatAssistantUpdate:
|
||||
)
|
||||
def test_llm(self, HttpApiAuth, add_chat_assistants_func, chat_assistant_llm_model_type, llm, expected_code, expected_message):
|
||||
dataset_id, _, chat_assistant_ids = add_chat_assistants_func
|
||||
llm_setting = {k: v for k, v in llm.items() if k != "llm_id"}
|
||||
llm_setting.setdefault("model_type", chat_assistant_llm_model_type)
|
||||
|
||||
payload = {"name": "llm_test", "dataset_ids": [dataset_id]}
|
||||
if "llm_id" in llm:
|
||||
payload["llm_id"] = llm["llm_id"]
|
||||
payload["llm_setting"] = llm_setting
|
||||
|
||||
llm_payload = dict(llm)
|
||||
llm_payload.setdefault("model_type", chat_assistant_llm_model_type)
|
||||
payload = {"name": "llm_test", "dataset_ids": [dataset_id], "llm": llm_payload}
|
||||
res = update_chat_assistant(HttpApiAuth, chat_assistant_ids[0], payload)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
res = get_chat_assistant(HttpApiAuth, chat_assistant_ids[0])
|
||||
for k, v in llm.items():
|
||||
if k == "llm_id":
|
||||
assert res["data"]["llm_id"] == v
|
||||
else:
|
||||
assert res["data"]["llm_setting"][k] == v
|
||||
res = list_chat_assistants(HttpApiAuth, {"id": chat_assistant_ids[0]})
|
||||
if llm:
|
||||
for k, v in llm.items():
|
||||
assert res["data"][0]["llm"][k] == v
|
||||
else:
|
||||
assert res["data"][0]["llm"]["model_name"] == "glm-4-flash@ZHIPU-AI"
|
||||
assert res["data"][0]["llm"]["temperature"] == 0.1
|
||||
assert res["data"][0]["llm"]["top_p"] == 0.3
|
||||
assert res["data"][0]["llm"]["presence_penalty"] == 0.4
|
||||
assert res["data"][0]["llm"]["frequency_penalty"] == 0.7
|
||||
assert res["data"][0]["llm"]["max_tokens"] == 512
|
||||
else:
|
||||
assert expected_message in res["message"]
|
||||
|
||||
@@ -157,18 +157,18 @@ class TestChatAssistantUpdate:
|
||||
@pytest.mark.parametrize(
|
||||
"prompt, expected_code, expected_message",
|
||||
[
|
||||
({}, 0, ""),
|
||||
({}, 100, "ValueError"),
|
||||
({"similarity_threshold": 0}, 0, ""),
|
||||
({"similarity_threshold": 1}, 0, ""),
|
||||
pytest.param({"similarity_threshold": -1}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"similarity_threshold": 10}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"similarity_threshold": "a"}, 0, "", marks=pytest.mark.skip),
|
||||
({"vector_similarity_weight": 0}, 0, ""),
|
||||
({"vector_similarity_weight": 1}, 0, ""),
|
||||
pytest.param({"vector_similarity_weight": -1}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"vector_similarity_weight": 10}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"vector_similarity_weight": "a"}, 0, "", marks=pytest.mark.skip),
|
||||
({"parameters": []}, 0, ""),
|
||||
({"keywords_similarity_weight": 0}, 0, ""),
|
||||
({"keywords_similarity_weight": 1}, 0, ""),
|
||||
pytest.param({"keywords_similarity_weight": -1}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"keywords_similarity_weight": 10}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"keywords_similarity_weight": "a"}, 0, "", marks=pytest.mark.skip),
|
||||
({"variables": []}, 0, ""),
|
||||
({"top_n": 0}, 0, ""),
|
||||
({"top_n": 1}, 0, ""),
|
||||
pytest.param({"top_n": -1}, 0, "", marks=pytest.mark.skip),
|
||||
@@ -181,52 +181,52 @@ class TestChatAssistantUpdate:
|
||||
pytest.param({"empty_response": 123}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"empty_response": True}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"empty_response": " "}, 0, "", marks=pytest.mark.skip),
|
||||
({"prologue": "Hello World"}, 0, ""),
|
||||
({"prologue": ""}, 0, ""),
|
||||
({"prologue": "!@#$%^&*()"}, 0, ""),
|
||||
({"prologue": "中文测试"}, 0, ""),
|
||||
pytest.param({"prologue": 123}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"prologue": True}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"prologue": " "}, 0, "", marks=pytest.mark.skip),
|
||||
({"quote": True}, 0, ""),
|
||||
({"quote": False}, 0, ""),
|
||||
({"system": "Hello World {knowledge}"}, 0, ""),
|
||||
({"system": "{knowledge}"}, 0, ""),
|
||||
({"system": "!@#$%^&*() {knowledge}"}, 0, ""),
|
||||
({"system": "中文测试 {knowledge}"}, 0, ""),
|
||||
({"system": "Hello World"}, 102, "Parameter 'knowledge' is not used"),
|
||||
({"system": "Hello World", "parameters": []}, 0, ""),
|
||||
pytest.param({"system": 123}, 100, """AttributeError("\'int\' object has no attribute \'find\'")""", marks=pytest.mark.skip),
|
||||
pytest.param({"system": True}, 100, """AttributeError("\'int\' object has no attribute \'find\'")""", marks=pytest.mark.skip),
|
||||
({"opener": "Hello World"}, 0, ""),
|
||||
({"opener": ""}, 0, ""),
|
||||
({"opener": "!@#$%^&*()"}, 0, ""),
|
||||
({"opener": "中文测试"}, 0, ""),
|
||||
pytest.param({"opener": 123}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"opener": True}, 0, "", marks=pytest.mark.skip),
|
||||
pytest.param({"opener": " "}, 0, "", marks=pytest.mark.skip),
|
||||
({"show_quote": True}, 0, ""),
|
||||
({"show_quote": False}, 0, ""),
|
||||
({"prompt": "Hello World {knowledge}"}, 0, ""),
|
||||
({"prompt": "{knowledge}"}, 0, ""),
|
||||
({"prompt": "!@#$%^&*() {knowledge}"}, 0, ""),
|
||||
({"prompt": "中文测试 {knowledge}"}, 0, ""),
|
||||
({"prompt": "Hello World"}, 102, "Parameter 'knowledge' is not used"),
|
||||
({"prompt": "Hello World", "variables": []}, 0, ""),
|
||||
pytest.param({"prompt": 123}, 100, """AttributeError("\'int\' object has no attribute \'find\'")""", marks=pytest.mark.skip),
|
||||
pytest.param({"prompt": True}, 100, """AttributeError("\'int\' object has no attribute \'find\'")""", marks=pytest.mark.skip),
|
||||
pytest.param({"unknown": "unknown"}, 0, "", marks=pytest.mark.skip),
|
||||
],
|
||||
)
|
||||
def test_prompt(self, HttpApiAuth, add_chat_assistants_func, prompt, expected_code, expected_message):
|
||||
dataset_id, _, chat_assistant_ids = add_chat_assistants_func
|
||||
|
||||
_PROMPT_CONFIG_KEYS = {"prologue", "quote", "system", "parameters", "empty_response"}
|
||||
|
||||
payload = {"name": "prompt_test", "dataset_ids": [dataset_id]}
|
||||
prompt_config = {}
|
||||
for k, v in prompt.items():
|
||||
if k in _PROMPT_CONFIG_KEYS:
|
||||
prompt_config[k] = v
|
||||
else:
|
||||
payload[k] = v
|
||||
if prompt_config:
|
||||
payload["prompt_config"] = prompt_config
|
||||
|
||||
payload = {"name": "prompt_test", "dataset_ids": [dataset_id], "prompt": prompt}
|
||||
res = update_chat_assistant(HttpApiAuth, chat_assistant_ids[0], payload)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
if not prompt:
|
||||
return
|
||||
res = get_chat_assistant(HttpApiAuth, chat_assistant_ids[0])
|
||||
for k, v in prompt.items():
|
||||
if k in _PROMPT_CONFIG_KEYS:
|
||||
assert res["data"]["prompt_config"][k] == v
|
||||
else:
|
||||
assert res["data"][k] == v
|
||||
res = list_chat_assistants(HttpApiAuth, {"id": chat_assistant_ids[0]})
|
||||
if prompt:
|
||||
for k, v in prompt.items():
|
||||
if k == "keywords_similarity_weight":
|
||||
assert res["data"][0]["prompt"][k] == 1 - v
|
||||
else:
|
||||
assert res["data"][0]["prompt"][k] == v
|
||||
else:
|
||||
assert res["data"]["prompt"][0]["similarity_threshold"] == 0.2
|
||||
assert res["data"]["prompt"][0]["keywords_similarity_weight"] == 0.7
|
||||
assert res["data"]["prompt"][0]["top_n"] == 6
|
||||
assert res["data"]["prompt"][0]["variables"] == [{"key": "knowledge", "optional": False}]
|
||||
assert res["data"]["prompt"][0]["rerank_model"] == ""
|
||||
assert res["data"]["prompt"][0]["empty_response"] == "Sorry! No relevant content was found in the knowledge base!"
|
||||
assert res["data"]["prompt"][0]["opener"] == "Hi! I'm your assistant. What can I do for you?"
|
||||
assert res["data"]["prompt"][0]["show_quote"] is True
|
||||
assert (
|
||||
res["data"]["prompt"][0]["prompt"]
|
||||
== 'You are an intelligent assistant. Please summarize the content of the dataset to answer the question. Please list the data in the dataset and answer in detail. When all dataset content is irrelevant to the question, your answer must include the sentence "The answer you are looking for is not found in the dataset!" Answers need to consider chat history.\n Here is the knowledge base:\n {knowledge}\n The above is the knowledge base.'
|
||||
)
|
||||
else:
|
||||
assert expected_message in res["message"]
|
||||
|
||||
@@ -235,54 +235,50 @@ class TestChatAssistantUpdate:
|
||||
dataset_id, _, chat_assistant_ids = add_chat_assistants_func
|
||||
chat_id = chat_assistant_ids[0]
|
||||
|
||||
# Auth: non-owned chat returns 109 "No authorization."
|
||||
res = patch_chat_assistant(HttpApiAuth, "invalid-chat-id", {"name": "anything"})
|
||||
assert res["code"] == 109
|
||||
assert res["message"] == "No authorization."
|
||||
res = update_chat_assistant(HttpApiAuth, "invalid-chat-id", {"name": "anything"})
|
||||
assert res["code"] == 102
|
||||
assert res["message"] == "You do not own the chat"
|
||||
|
||||
# PATCH: toggle quote via prompt_config
|
||||
res = patch_chat_assistant(HttpApiAuth, chat_id, {"prompt_config": {"quote": False}})
|
||||
res = update_chat_assistant(HttpApiAuth, chat_id, {"show_quotation": False, "dataset_ids": [dataset_id]})
|
||||
assert res["code"] == 0
|
||||
|
||||
# PATCH: invalid llm_id
|
||||
res = patch_chat_assistant(
|
||||
res = update_chat_assistant(
|
||||
HttpApiAuth,
|
||||
chat_id,
|
||||
{"llm_id": "unknown-llm-model", "llm_setting": {"model_type": chat_assistant_llm_model_type}},
|
||||
{"llm": {"model_name": "unknown-llm-model", "model_type": chat_assistant_llm_model_type}},
|
||||
)
|
||||
assert res["code"] == 102
|
||||
assert "`llm_id` unknown-llm-model doesn't exist" in res["message"]
|
||||
assert "`model_name` unknown-llm-model doesn't exist" in res["message"]
|
||||
|
||||
# PATCH: invalid rerank_id
|
||||
res = patch_chat_assistant(HttpApiAuth, chat_id, {"rerank_id": "unknown-rerank-model"})
|
||||
res = update_chat_assistant(
|
||||
HttpApiAuth,
|
||||
chat_id,
|
||||
{"prompt": {"rerank_model": "unknown-rerank-model"}},
|
||||
)
|
||||
assert res["code"] == 102
|
||||
assert "`rerank_id` unknown-rerank-model doesn't exist" in res["message"]
|
||||
assert "`rerank_model` unknown-rerank-model doesn't exist" in res["message"]
|
||||
|
||||
# PATCH: empty name
|
||||
res = patch_chat_assistant(HttpApiAuth, chat_id, {"name": ""})
|
||||
res = update_chat_assistant(HttpApiAuth, chat_id, {"name": ""})
|
||||
assert res["code"] == 102
|
||||
assert res["message"] == "`name` cannot be empty."
|
||||
|
||||
# PATCH: duplicate name
|
||||
res = patch_chat_assistant(HttpApiAuth, chat_id, {"name": "test_chat_assistant_1"})
|
||||
res = update_chat_assistant(HttpApiAuth, chat_id, {"name": "test_chat_assistant_1"})
|
||||
assert res["code"] == 102
|
||||
assert res["message"] == "Duplicated chat name."
|
||||
assert res["message"] == "Duplicated chat name in updating chat."
|
||||
|
||||
# PATCH: prompt_config with unused parameter
|
||||
res = patch_chat_assistant(
|
||||
res = update_chat_assistant(
|
||||
HttpApiAuth,
|
||||
chat_id,
|
||||
{"prompt_config": {"system": "No required placeholder", "parameters": [{"key": "knowledge", "optional": False}]}},
|
||||
{"prompt": {"prompt": "No required placeholder", "variables": [{"key": "knowledge", "optional": False}]}},
|
||||
)
|
||||
assert res["code"] == 102
|
||||
assert "Parameter 'knowledge' is not used" in res["message"]
|
||||
|
||||
# PATCH: icon (was "avatar" in old SDK)
|
||||
res = patch_chat_assistant(HttpApiAuth, chat_id, {"icon": "raw-avatar-value"})
|
||||
res = update_chat_assistant(HttpApiAuth, chat_id, {"avatar": "raw-avatar-value"})
|
||||
assert res["code"] == 0
|
||||
listed = get_chat_assistant(HttpApiAuth, chat_id)
|
||||
listed = list_chat_assistants(HttpApiAuth, {"id": chat_id})
|
||||
assert listed["code"] == 0
|
||||
assert listed["data"]["icon"] == "raw-avatar-value"
|
||||
assert listed["data"][0]["avatar"] == "raw-avatar-value"
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_update_unparsed_dataset_guard_p2(self, HttpApiAuth, add_dataset_func, clear_chat_assistants):
|
||||
@@ -291,6 +287,6 @@ class TestChatAssistantUpdate:
|
||||
assert create_res["code"] == 0
|
||||
|
||||
chat_id = create_res["data"]["id"]
|
||||
res = patch_chat_assistant(HttpApiAuth, chat_id, {"dataset_ids": [dataset_id]})
|
||||
res = update_chat_assistant(HttpApiAuth, chat_id, {"dataset_ids": [dataset_id]})
|
||||
assert res["code"] == 102
|
||||
assert "doesn't own parsed file" in res["message"]
|
||||
|
||||
Reference in New Issue
Block a user