mirror of
https://github.com/langgenius/dify.git
synced 2026-09-03 23:47:16 +08:00
test: migrate app runtime sessions and ORM models to SQLite (#40590)
This commit is contained in:
parent
f2dfa462e1
commit
4f81005662
@ -3,9 +3,11 @@ from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from core.app.app_config.easy_ui_based_app.dataset.manager import DatasetConfigManager
|
||||
from core.entities.agent_entities import PlanningStrategy
|
||||
from models.dataset import Dataset
|
||||
from models.model import AppMode
|
||||
|
||||
# ==============================
|
||||
@ -33,12 +35,16 @@ def base_config(valid_uuid):
|
||||
|
||||
@pytest.fixture
|
||||
def mock_dataset_service(mocker: MockerFixture, valid_uuid):
|
||||
mock_dataset = MagicMock()
|
||||
mock_dataset.tenant_id = "tenant1"
|
||||
dataset = Dataset(
|
||||
id=valid_uuid,
|
||||
tenant_id="tenant1",
|
||||
name="Test Dataset",
|
||||
created_by="account-1",
|
||||
)
|
||||
|
||||
mocker.patch(
|
||||
"core.app.app_config.easy_ui_based_app.dataset.manager.DatasetService.get_dataset",
|
||||
return_value=mock_dataset,
|
||||
return_value=dataset,
|
||||
)
|
||||
|
||||
|
||||
@ -206,19 +212,21 @@ class TestDatasetConfigManagerConvert:
|
||||
|
||||
|
||||
class TestValidateAndSetDefaults:
|
||||
def test_validate_sets_defaults(self):
|
||||
def test_validate_sets_defaults(self, unbound_session: Session):
|
||||
config = {}
|
||||
updated, fields = DatasetConfigManager.validate_and_set_defaults("tenant1", AppMode.CHAT, config, MagicMock())
|
||||
updated, fields = DatasetConfigManager.validate_and_set_defaults(
|
||||
"tenant1", AppMode.CHAT, config, unbound_session
|
||||
)
|
||||
assert "dataset_configs" in updated
|
||||
assert updated["dataset_configs"]["retrieval_model"] == "single"
|
||||
assert isinstance(fields, list)
|
||||
|
||||
def test_validate_raises_when_dataset_configs_not_dict(self):
|
||||
def test_validate_raises_when_dataset_configs_not_dict(self, unbound_session: Session):
|
||||
config = {"dataset_configs": "invalid"}
|
||||
with pytest.raises(AttributeError):
|
||||
DatasetConfigManager.validate_and_set_defaults("tenant1", AppMode.CHAT, config, MagicMock())
|
||||
DatasetConfigManager.validate_and_set_defaults("tenant1", AppMode.CHAT, config, unbound_session)
|
||||
|
||||
def test_validate_requires_query_variable_in_completion_mode(self, valid_uuid):
|
||||
def test_validate_requires_query_variable_in_completion_mode(self, valid_uuid, unbound_session: Session):
|
||||
config = {
|
||||
"dataset_configs": {
|
||||
"datasets": {
|
||||
@ -228,7 +236,7 @@ class TestValidateAndSetDefaults:
|
||||
}
|
||||
}
|
||||
with pytest.raises(ValueError):
|
||||
DatasetConfigManager.validate_and_set_defaults("tenant1", AppMode.COMPLETION, config, MagicMock())
|
||||
DatasetConfigManager.validate_and_set_defaults("tenant1", AppMode.COMPLETION, config, unbound_session)
|
||||
|
||||
|
||||
# ==============================
|
||||
@ -237,37 +245,37 @@ class TestValidateAndSetDefaults:
|
||||
|
||||
|
||||
class TestExtractDatasetConfig:
|
||||
def test_extract_sets_defaults(self):
|
||||
def test_extract_sets_defaults(self, unbound_session: Session):
|
||||
config = {}
|
||||
result = DatasetConfigManager.extract_dataset_config_for_legacy_compatibility(
|
||||
"tenant1", AppMode.CHAT, config, MagicMock()
|
||||
"tenant1", AppMode.CHAT, config, unbound_session
|
||||
)
|
||||
assert "agent_mode" in result
|
||||
assert result["agent_mode"]["enabled"] is False
|
||||
assert result["agent_mode"]["tools"] == []
|
||||
|
||||
def test_extract_invalid_agent_mode_type(self):
|
||||
def test_extract_invalid_agent_mode_type(self, unbound_session: Session):
|
||||
config = {"agent_mode": "invalid"}
|
||||
with pytest.raises(ValueError):
|
||||
DatasetConfigManager.extract_dataset_config_for_legacy_compatibility(
|
||||
"tenant1", AppMode.CHAT, config, MagicMock()
|
||||
"tenant1", AppMode.CHAT, config, unbound_session
|
||||
)
|
||||
|
||||
def test_extract_invalid_enabled_type(self):
|
||||
def test_extract_invalid_enabled_type(self, unbound_session: Session):
|
||||
config = {"agent_mode": {"enabled": "yes"}}
|
||||
with pytest.raises(ValueError):
|
||||
DatasetConfigManager.extract_dataset_config_for_legacy_compatibility(
|
||||
"tenant1", AppMode.CHAT, config, MagicMock()
|
||||
"tenant1", AppMode.CHAT, config, unbound_session
|
||||
)
|
||||
|
||||
def test_extract_invalid_tools_type(self):
|
||||
def test_extract_invalid_tools_type(self, unbound_session: Session):
|
||||
config = {"agent_mode": {"enabled": True, "tools": "invalid"}}
|
||||
with pytest.raises(ValueError):
|
||||
DatasetConfigManager.extract_dataset_config_for_legacy_compatibility(
|
||||
"tenant1", AppMode.CHAT, config, MagicMock()
|
||||
"tenant1", AppMode.CHAT, config, unbound_session
|
||||
)
|
||||
|
||||
def test_extract_invalid_uuid(self, mocker: MockerFixture):
|
||||
def test_extract_invalid_uuid(self, mocker: MockerFixture, unbound_session: Session):
|
||||
invalid_uuid = "not-a-uuid"
|
||||
config = {
|
||||
"agent_mode": {
|
||||
@ -278,10 +286,10 @@ class TestExtractDatasetConfig:
|
||||
}
|
||||
with pytest.raises(ValueError):
|
||||
DatasetConfigManager.extract_dataset_config_for_legacy_compatibility(
|
||||
"tenant1", AppMode.CHAT, config, MagicMock()
|
||||
"tenant1", AppMode.CHAT, config, unbound_session
|
||||
)
|
||||
|
||||
def test_extract_dataset_not_exists(self, valid_uuid, mocker: MockerFixture):
|
||||
def test_extract_dataset_not_exists(self, valid_uuid, mocker: MockerFixture, unbound_session: Session):
|
||||
mocker.patch(
|
||||
"core.app.app_config.easy_ui_based_app.dataset.manager.DatasetService.get_dataset",
|
||||
return_value=None,
|
||||
@ -295,7 +303,7 @@ class TestExtractDatasetConfig:
|
||||
}
|
||||
with pytest.raises(ValueError):
|
||||
DatasetConfigManager.extract_dataset_config_for_legacy_compatibility(
|
||||
"tenant1", AppMode.CHAT, config, MagicMock()
|
||||
"tenant1", AppMode.CHAT, config, unbound_session
|
||||
)
|
||||
|
||||
|
||||
@ -305,31 +313,41 @@ class TestExtractDatasetConfig:
|
||||
|
||||
|
||||
class TestIsDatasetExists:
|
||||
def test_dataset_exists_true(self, mocker: MockerFixture, valid_uuid):
|
||||
mock_dataset = MagicMock()
|
||||
mock_dataset.tenant_id = "tenant1"
|
||||
def test_dataset_exists_true(self, mocker: MockerFixture, valid_uuid, unbound_session: Session):
|
||||
dataset = Dataset(
|
||||
id=valid_uuid,
|
||||
tenant_id="tenant1",
|
||||
name="Test Dataset",
|
||||
created_by="account-1",
|
||||
)
|
||||
mocker.patch(
|
||||
"core.app.app_config.easy_ui_based_app.dataset.manager.DatasetService.get_dataset",
|
||||
return_value=mock_dataset,
|
||||
return_value=dataset,
|
||||
)
|
||||
|
||||
assert DatasetConfigManager.is_dataset_exists("tenant1", valid_uuid, MagicMock())
|
||||
assert DatasetConfigManager.is_dataset_exists("tenant1", valid_uuid, unbound_session)
|
||||
|
||||
def test_dataset_exists_false_when_not_found(self, mocker: MockerFixture, valid_uuid):
|
||||
def test_dataset_exists_false_when_not_found(self, mocker: MockerFixture, valid_uuid, unbound_session: Session):
|
||||
mocker.patch(
|
||||
"core.app.app_config.easy_ui_based_app.dataset.manager.DatasetService.get_dataset",
|
||||
return_value=None,
|
||||
)
|
||||
assert not DatasetConfigManager.is_dataset_exists("tenant1", valid_uuid, MagicMock())
|
||||
assert not DatasetConfigManager.is_dataset_exists("tenant1", valid_uuid, unbound_session)
|
||||
|
||||
def test_dataset_exists_false_when_tenant_mismatch(self, mocker: MockerFixture, valid_uuid):
|
||||
mock_dataset = MagicMock()
|
||||
mock_dataset.tenant_id = "other"
|
||||
def test_dataset_exists_false_when_tenant_mismatch(
|
||||
self, mocker: MockerFixture, valid_uuid, unbound_session: Session
|
||||
):
|
||||
dataset = Dataset(
|
||||
id=valid_uuid,
|
||||
tenant_id="other",
|
||||
name="Other Tenant Dataset",
|
||||
created_by="account-2",
|
||||
)
|
||||
mocker.patch(
|
||||
"core.app.app_config.easy_ui_based_app.dataset.manager.DatasetService.get_dataset",
|
||||
return_value=mock_dataset,
|
||||
return_value=dataset,
|
||||
)
|
||||
assert not DatasetConfigManager.is_dataset_exists("tenant1", valid_uuid, MagicMock())
|
||||
assert not DatasetConfigManager.is_dataset_exists("tenant1", valid_uuid, unbound_session)
|
||||
|
||||
|
||||
# ==============================
|
||||
@ -338,7 +356,7 @@ class TestIsDatasetExists:
|
||||
|
||||
|
||||
class TestExtractDatasetConfigForLegacyCompatibility:
|
||||
def test_skips_empty_tool_entry(self):
|
||||
def test_skips_empty_tool_entry(self, unbound_session: Session):
|
||||
# A malformed empty tool dict in agent_mode.tools must be skipped, not
|
||||
# crash with `IndexError` on `list(tool.keys())[0]`. The sibling
|
||||
# convert() already guards this with `if len(tool) == 1`.
|
||||
@ -351,7 +369,7 @@ class TestExtractDatasetConfigForLegacyCompatibility:
|
||||
}
|
||||
|
||||
result = DatasetConfigManager.extract_dataset_config_for_legacy_compatibility(
|
||||
"tenant1", AppMode.CHAT, config, MagicMock()
|
||||
"tenant1", AppMode.CHAT, config, unbound_session
|
||||
)
|
||||
|
||||
assert result["agent_mode"]["tools"] == [{}]
|
||||
|
||||
@ -1,14 +1,32 @@
|
||||
from types import SimpleNamespace
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
from core.app.apps.advanced_chat.app_config_manager import AdvancedChatAppConfigManager
|
||||
from models.model import AppMode
|
||||
from models.model import App, AppMode
|
||||
from models.workflow import Workflow, WorkflowType
|
||||
|
||||
|
||||
def _app() -> App:
|
||||
return App(id="app-1", tenant_id="tenant-1", name="Advanced Chat App", mode=AppMode.ADVANCED_CHAT)
|
||||
|
||||
|
||||
def _workflow() -> Workflow:
|
||||
return Workflow(
|
||||
id="wf-1",
|
||||
tenant_id="tenant-1",
|
||||
app_id="app-1",
|
||||
type=WorkflowType.CHAT,
|
||||
version=Workflow.VERSION_DRAFT,
|
||||
graph="{}",
|
||||
features=json.dumps({}),
|
||||
created_by="account-1",
|
||||
)
|
||||
|
||||
|
||||
class TestAdvancedChatAppConfigManager:
|
||||
def test_get_app_config(self):
|
||||
app_model = SimpleNamespace(id="app-1", tenant_id="tenant-1", mode=AppMode.ADVANCED_CHAT.value)
|
||||
workflow = SimpleNamespace(id="wf-1", features_dict={})
|
||||
app_model = _app()
|
||||
workflow = _workflow()
|
||||
|
||||
with (
|
||||
patch(
|
||||
|
||||
@ -3,10 +3,11 @@ app_model_config-shaped dict bridge that lets an Agent App ride the chat pipelin
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
import json
|
||||
|
||||
from core.app.apps.agent_app.app_config_manager import AgentAppConfigManager
|
||||
from models.agent_config_entities import AgentSoulConfig
|
||||
from models.model import App, AppMode, AppModelConfig
|
||||
|
||||
|
||||
def _soul() -> AgentSoulConfig:
|
||||
@ -27,6 +28,13 @@ def _soul() -> AgentSoulConfig:
|
||||
)
|
||||
|
||||
|
||||
def _app_model_config(**values: object) -> AppModelConfig:
|
||||
config = AppModelConfig(app_id="app-1")
|
||||
for key, value in values.items():
|
||||
setattr(config, key, json.dumps(value) if isinstance(value, (dict, list)) else value)
|
||||
return config
|
||||
|
||||
|
||||
def test_model_and_prompt_come_from_soul():
|
||||
d = AgentAppConfigManager._synthesize_config_dict(_soul(), None, annotation_reply=None)
|
||||
assert d["model"] == {
|
||||
@ -44,17 +52,15 @@ def test_model_and_prompt_come_from_soul():
|
||||
|
||||
def test_feature_flags_come_from_app_model_config_when_present():
|
||||
# Q3: opener/follow-up/etc. live on app_model_config; model/prompt stay from Soul.
|
||||
fake_amc = SimpleNamespace(
|
||||
to_dict=lambda **_: {
|
||||
"opening_statement": "Hi, I'm Iris.",
|
||||
"suggested_questions_after_answer": {"enabled": True},
|
||||
"model": {"provider": "should-be-overridden", "name": "old"},
|
||||
"pre_prompt": "old prompt",
|
||||
}
|
||||
app_model_config = _app_model_config(
|
||||
opening_statement="Hi, I'm Iris.",
|
||||
suggested_questions_after_answer={"enabled": True},
|
||||
model={"provider": "should-be-overridden", "name": "old"},
|
||||
pre_prompt="old prompt",
|
||||
)
|
||||
d = AgentAppConfigManager._synthesize_config_dict(
|
||||
_soul(),
|
||||
fake_amc,
|
||||
app_model_config,
|
||||
annotation_reply={"enabled": False}, # type: ignore[arg-type]
|
||||
)
|
||||
# feature flags preserved
|
||||
@ -80,18 +86,16 @@ def test_missing_soul_model_leaves_no_model_key():
|
||||
|
||||
|
||||
def test_soul_file_upload_overrides_legacy_app_model_config():
|
||||
fake_amc = SimpleNamespace(
|
||||
to_dict=lambda **_: {
|
||||
"file_upload": {
|
||||
"enabled": False,
|
||||
"image": {"enabled": False},
|
||||
},
|
||||
}
|
||||
app_model_config = _app_model_config(
|
||||
file_upload={
|
||||
"enabled": False,
|
||||
"image": {"enabled": False},
|
||||
},
|
||||
)
|
||||
|
||||
d = AgentAppConfigManager._synthesize_config_dict(
|
||||
AgentSoulConfig(),
|
||||
fake_amc,
|
||||
app_model_config,
|
||||
annotation_reply={"enabled": False}, # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
@ -115,13 +119,14 @@ def test_prompt_type_defaults_to_simple():
|
||||
def test_get_app_config_has_null_model_config_id_without_legacy_row():
|
||||
# An Agent App has no app_model_config row; the conversation's
|
||||
# app_model_config_id (a UUID column) must be NULL, not "".
|
||||
app_model = SimpleNamespace(
|
||||
app_model = App(
|
||||
tenant_id="11111111-1111-1111-1111-111111111111",
|
||||
id="22222222-2222-2222-2222-222222222222",
|
||||
mode="agent",
|
||||
name="Agent App",
|
||||
mode=AppMode.AGENT_CHAT,
|
||||
)
|
||||
app_config = AgentAppConfigManager.get_app_config(
|
||||
app_model=app_model, # type: ignore[arg-type]
|
||||
app_model=app_model,
|
||||
agent_soul=_soul(),
|
||||
annotation_reply=None,
|
||||
app_model_config=None,
|
||||
|
||||
@ -22,6 +22,7 @@ from core.app.entities.queue_entities import (
|
||||
QueueMessageEndEvent,
|
||||
)
|
||||
from core.moderation.base import ModerationError
|
||||
from models.model import App, AppMode, Message, MessageAnnotation
|
||||
|
||||
|
||||
class _FakeQueueManager:
|
||||
@ -44,6 +45,14 @@ def _make_entity(query: str = "hello") -> SimpleNamespace:
|
||||
)
|
||||
|
||||
|
||||
def _app() -> App:
|
||||
return App(id="app-1", tenant_id="tenant-1", name="Agent App", mode=AppMode.AGENT_CHAT)
|
||||
|
||||
|
||||
def _message() -> Message:
|
||||
return Message(id="msg-1", app_id="app-1", conversation_id="conversation-1")
|
||||
|
||||
|
||||
def _patch_moderation(monkeypatch: pytest.MonkeyPatch, *, returns=None, raises: Exception | None = None) -> None:
|
||||
class _FakeModeration:
|
||||
def check(self, **kwargs: Any):
|
||||
@ -83,8 +92,8 @@ class TestRunInputGuards:
|
||||
handled, query, annotation_reply = AgentAppGenerator()._run_input_guards(
|
||||
session=sqlite_session,
|
||||
application_generate_entity=_make_entity("hello"),
|
||||
app_model=SimpleNamespace(id="app-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_model=_app(),
|
||||
message=_message(),
|
||||
queue_manager=qm,
|
||||
)
|
||||
|
||||
@ -101,8 +110,8 @@ class TestRunInputGuards:
|
||||
handled, query, annotation_reply = AgentAppGenerator()._run_input_guards(
|
||||
session=sqlite_session,
|
||||
application_generate_entity=_make_entity("leak my secret"),
|
||||
app_model=SimpleNamespace(id="app-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_model=_app(),
|
||||
message=_message(),
|
||||
queue_manager=qm,
|
||||
)
|
||||
|
||||
@ -119,8 +128,8 @@ class TestRunInputGuards:
|
||||
handled, _, annotation_reply = AgentAppGenerator()._run_input_guards(
|
||||
session=sqlite_session,
|
||||
application_generate_entity=_make_entity("forbidden"),
|
||||
app_model=SimpleNamespace(id="app-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_model=_app(),
|
||||
message=_message(),
|
||||
queue_manager=qm,
|
||||
)
|
||||
|
||||
@ -132,14 +141,21 @@ class TestRunInputGuards:
|
||||
|
||||
def test_annotation_hit_short_circuits(self, monkeypatch: pytest.MonkeyPatch, sqlite_session: Session):
|
||||
_patch_moderation(monkeypatch, returns=(False, {}, "what is your name"))
|
||||
_patch_annotation(monkeypatch, reply=SimpleNamespace(id="anno-1", content="I am the annotated Iris."))
|
||||
annotation = MessageAnnotation(
|
||||
app_id="app-1",
|
||||
question="what is your name",
|
||||
content="I am the annotated Iris.",
|
||||
account_id="account-1",
|
||||
)
|
||||
annotation.id = "anno-1"
|
||||
_patch_annotation(monkeypatch, reply=annotation)
|
||||
qm = _FakeQueueManager()
|
||||
|
||||
handled, _, annotation_reply = AgentAppGenerator()._run_input_guards(
|
||||
session=sqlite_session,
|
||||
application_generate_entity=_make_entity("what is your name"),
|
||||
app_model=SimpleNamespace(id="app-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_model=_app(),
|
||||
message=_message(),
|
||||
queue_manager=qm,
|
||||
)
|
||||
|
||||
|
||||
@ -1,17 +1,27 @@
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from core.app.app_config.entities import EasyUIBasedAppModelConfigFrom, ModelConfigEntity, PromptTemplateEntity
|
||||
from core.app.apps.chat.app_config_manager import ChatAppConfigManager
|
||||
from models.model import AppMode
|
||||
from models.model import App, AppMode, AppModelConfig
|
||||
|
||||
|
||||
def _app() -> App:
|
||||
return App(id="app-1", tenant_id="tenant-1", name="Chat App", mode=AppMode.CHAT)
|
||||
|
||||
|
||||
def _app_model_config() -> AppModelConfig:
|
||||
config = AppModelConfig(app_id="app-1", model=json.dumps({"model": "m"}))
|
||||
config.id = "config-1"
|
||||
return config
|
||||
|
||||
|
||||
class TestChatAppConfigManager:
|
||||
def test_get_app_config_uses_override_dict(self):
|
||||
app_model = SimpleNamespace(id="app-1", tenant_id="tenant-1", mode=AppMode.CHAT.value)
|
||||
app_model_config = SimpleNamespace(id="config-1", to_dict=lambda: {"model": "m"})
|
||||
app_model = _app()
|
||||
app_model_config = _app_model_config()
|
||||
override = {"model": "override"}
|
||||
|
||||
model_entity = ModelConfigEntity(provider="p", model="m")
|
||||
@ -45,11 +55,8 @@ class TestChatAppConfigManager:
|
||||
assert app_config.app_mode == AppMode.CHAT
|
||||
|
||||
def test_get_app_config_uses_injected_annotation_reply(self):
|
||||
app_model = SimpleNamespace(id="app-1", tenant_id="tenant-1", mode=AppMode.CHAT.value)
|
||||
app_model_config = SimpleNamespace(
|
||||
id="config-1",
|
||||
to_dict=MagicMock(return_value={"model": "m"}),
|
||||
)
|
||||
app_model = _app()
|
||||
app_model_config = _app_model_config()
|
||||
annotation_reply = {"enabled": False}
|
||||
|
||||
model_entity = ModelConfigEntity(provider="p", model="m")
|
||||
@ -59,6 +66,7 @@ class TestChatAppConfigManager:
|
||||
)
|
||||
|
||||
with (
|
||||
patch.object(app_model_config, "to_dict", wraps=app_model_config.to_dict) as to_dict,
|
||||
patch("core.app.apps.chat.app_config_manager.ModelConfigManager.convert", return_value=model_entity),
|
||||
patch(
|
||||
"core.app.apps.chat.app_config_manager.PromptTemplateConfigManager.convert", return_value=prompt_entity
|
||||
@ -76,7 +84,7 @@ class TestChatAppConfigManager:
|
||||
annotation_reply=annotation_reply,
|
||||
)
|
||||
|
||||
app_model_config.to_dict.assert_called_once_with(annotation_reply=annotation_reply)
|
||||
to_dict.assert_called_once_with(annotation_reply=annotation_reply)
|
||||
|
||||
def test_config_validate_filters_related_keys(self, unbound_session: Session):
|
||||
config = {"extra": 1}
|
||||
|
||||
@ -8,6 +8,7 @@ from core.workflow.system_variables import build_system_variables
|
||||
from graphon.entities import WorkflowStartReason
|
||||
from graphon.runtime import GraphRuntimeState, VariablePool
|
||||
from graphon.variables.segments import StringSegment
|
||||
from models.account import Account
|
||||
|
||||
|
||||
def _build_converter():
|
||||
@ -28,7 +29,8 @@ def _build_converter():
|
||||
workflow_execution_id="run-1",
|
||||
call_depth=0,
|
||||
)
|
||||
account = SimpleNamespace(id="acc-1", name="tester", email="tester@example.com")
|
||||
account = Account(name="tester", email="tester@example.com")
|
||||
account.id = "acc-1"
|
||||
return WorkflowResponseConverter(
|
||||
application_generate_entity=app_entity,
|
||||
user=account,
|
||||
|
||||
@ -5,6 +5,7 @@ from core.app.entities.app_invoke_entities import InvokeFrom
|
||||
from core.workflow.system_variables import build_system_variables
|
||||
from graphon.entities import WorkflowStartReason
|
||||
from graphon.runtime import GraphRuntimeState, VariablePool
|
||||
from models.account import Account
|
||||
|
||||
|
||||
def _build_converter() -> WorkflowResponseConverter:
|
||||
@ -26,7 +27,8 @@ def _build_converter() -> WorkflowResponseConverter:
|
||||
workflow_execution_id="run-1",
|
||||
call_depth=0,
|
||||
)
|
||||
account = SimpleNamespace(id="acc-1", name="tester", email="tester@example.com")
|
||||
account = Account(name="tester", email="tester@example.com")
|
||||
account.id = "acc-1"
|
||||
return WorkflowResponseConverter(
|
||||
application_generate_entity=app_entity,
|
||||
user=account,
|
||||
|
||||
@ -15,7 +15,8 @@ from core.app.app_config.entities import (
|
||||
from core.app.apps.exc import GenerateTaskStoppedError
|
||||
from core.app.apps.message_based_app_generator import MessageBasedAppGenerator
|
||||
from core.app.entities.app_invoke_entities import ChatAppGenerateEntity, InvokeFrom
|
||||
from models.model import AppMode
|
||||
from models.account import Account
|
||||
from models.model import App, AppMode, Conversation, Message
|
||||
from services.errors.app_model_config import AppModelConfigBrokenError
|
||||
|
||||
|
||||
@ -45,6 +46,22 @@ class DummyCompletionGenerateEntity:
|
||||
self.model_conf = DummyModelConf()
|
||||
|
||||
|
||||
def _app(*, app_id: str = "app") -> App:
|
||||
return App(
|
||||
id=app_id,
|
||||
tenant_id="tenant-id",
|
||||
name="Message App",
|
||||
mode=AppMode.CHAT,
|
||||
app_model_config_id=None,
|
||||
)
|
||||
|
||||
|
||||
def _account() -> Account:
|
||||
account = Account(name="Message User", email="message-user@example.com")
|
||||
account.id = "user-id"
|
||||
return account
|
||||
|
||||
|
||||
def _make_app_config(app_mode: AppMode) -> EasyUIBasedAppConfig:
|
||||
return EasyUIBasedAppConfig(
|
||||
tenant_id="tenant-id",
|
||||
@ -138,24 +155,24 @@ class TestMessageBasedAppGeneratorExtras:
|
||||
generator._handle_response(
|
||||
application_generate_entity=_make_chat_generate_entity(_make_app_config(AppMode.CHAT)),
|
||||
queue_manager=SimpleNamespace(),
|
||||
conversation=SimpleNamespace(id="conv"),
|
||||
message=SimpleNamespace(id="msg"),
|
||||
user=SimpleNamespace(),
|
||||
conversation=Conversation(id="conv", app_id="app"),
|
||||
message=Message(id="msg", app_id="app", conversation_id="conv"),
|
||||
user=_account(),
|
||||
stream=False,
|
||||
)
|
||||
|
||||
def test_get_app_model_config_requires_valid_config(self, sqlite_session: Session):
|
||||
generator = MessageBasedAppGenerator()
|
||||
app_model = SimpleNamespace(id="app", app_model_config_id=None, app_model_config=None)
|
||||
app_model = _app()
|
||||
session = sqlite_session
|
||||
|
||||
with pytest.raises(AppModelConfigBrokenError):
|
||||
generator._get_app_model_config(app_model, conversation=None, session=session)
|
||||
|
||||
conversation = SimpleNamespace(app_model_config_id="missing-id")
|
||||
conversation = Conversation(id="conversation-id", app_id="app", app_model_config_id="missing-id")
|
||||
with pytest.raises(AppModelConfigBrokenError):
|
||||
generator._get_app_model_config(
|
||||
app_model=SimpleNamespace(id="app"),
|
||||
app_model=_app(),
|
||||
conversation=conversation,
|
||||
session=session,
|
||||
)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import UTC, datetime
|
||||
from types import SimpleNamespace
|
||||
|
||||
@ -48,6 +49,22 @@ from graphon.node_events import NodeRunResult
|
||||
from graphon.runtime import GraphRuntimeState, VariablePool
|
||||
from graphon.variables.segments import StringSegment
|
||||
from graphon.variables.variables import StringVariable
|
||||
from models.workflow import Workflow, WorkflowType
|
||||
|
||||
|
||||
def _workflow(graph: dict[str, object] | None = None) -> Workflow:
|
||||
return Workflow.new(
|
||||
tenant_id="tenant",
|
||||
app_id="app",
|
||||
type=WorkflowType.WORKFLOW,
|
||||
version=Workflow.VERSION_DRAFT,
|
||||
graph=json.dumps(graph or {}, default=str),
|
||||
features="{}",
|
||||
created_by="account",
|
||||
environment_variables=[],
|
||||
conversation_variables=[],
|
||||
rag_pipeline_variables=[],
|
||||
)
|
||||
|
||||
|
||||
class TestWorkflowBasedAppRunner:
|
||||
@ -122,7 +139,7 @@ class TestWorkflowBasedAppRunner:
|
||||
def test_prepare_single_node_execution_requires_run(self):
|
||||
runner = WorkflowBasedAppRunner(queue_manager=SimpleNamespace(), app_id="app")
|
||||
|
||||
workflow = SimpleNamespace(environment_variables=[], graph_dict={})
|
||||
workflow = _workflow()
|
||||
|
||||
with pytest.raises(ValueError, match="Neither single_iteration_run nor single_loop_run"):
|
||||
runner._prepare_single_node_execution(workflow, None, None, user_id="00000000-0000-0000-0000-000000000001")
|
||||
@ -138,7 +155,8 @@ class TestWorkflowBasedAppRunner:
|
||||
"nodes": [{"id": "node-1", "data": {"type": "start", "version": "1"}}],
|
||||
"edges": [],
|
||||
}
|
||||
workflow = SimpleNamespace(tenant_id="tenant", id="workflow", graph_dict=graph_config)
|
||||
workflow = _workflow(graph_config)
|
||||
workflow.id = "workflow"
|
||||
|
||||
monkeypatch.setattr(
|
||||
"core.app.apps.workflow_app_runner.Graph.init",
|
||||
@ -191,7 +209,8 @@ class TestWorkflowBasedAppRunner:
|
||||
"nodes": [{"id": "node-1", "data": {"type": "start", "version": "1"}}],
|
||||
"edges": [],
|
||||
}
|
||||
workflow = SimpleNamespace(tenant_id="tenant", id="workflow", graph_dict=graph_config)
|
||||
workflow = _workflow(graph_config)
|
||||
workflow.id = "workflow"
|
||||
captured = {}
|
||||
|
||||
def fake_from_graph_init_context(**kwargs):
|
||||
@ -256,10 +275,8 @@ class TestWorkflowBasedAppRunner:
|
||||
start_at=0.0,
|
||||
)
|
||||
|
||||
workflow = SimpleNamespace(
|
||||
tenant_id="tenant",
|
||||
id="workflow",
|
||||
graph_dict={
|
||||
workflow = _workflow(
|
||||
{
|
||||
"nodes": [
|
||||
{"id": "loop-node", "data": {"type": "loop", "version": "1", "title": "Loop"}},
|
||||
{
|
||||
@ -273,8 +290,9 @@ class TestWorkflowBasedAppRunner:
|
||||
},
|
||||
],
|
||||
"edges": [],
|
||||
},
|
||||
}
|
||||
)
|
||||
workflow.id = "workflow"
|
||||
|
||||
class _LoopNodeCls:
|
||||
@staticmethod
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import json
|
||||
from datetime import UTC, datetime
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
@ -26,6 +27,7 @@ from graphon.graph_events import GraphRunPausedEvent
|
||||
from graphon.runtime import GraphRuntimeState, VariablePool
|
||||
from models.account import Account
|
||||
from models.human_input import HumanInputForm, HumanInputFormRecipient, RecipientType
|
||||
from models.workflow import Workflow, WorkflowType
|
||||
|
||||
|
||||
class _RecordingWorkflowAppRunner(WorkflowAppRunner):
|
||||
@ -92,12 +94,19 @@ def _build_runner():
|
||||
workflow_execution_id="run-id",
|
||||
user_id="user-id",
|
||||
)
|
||||
workflow = SimpleNamespace(
|
||||
graph_dict={},
|
||||
workflow = Workflow.new(
|
||||
tenant_id="tenant-id",
|
||||
environment_variables={},
|
||||
id="workflow-id",
|
||||
app_id="app-id",
|
||||
type=WorkflowType.WORKFLOW,
|
||||
version=Workflow.VERSION_DRAFT,
|
||||
graph=json.dumps({}),
|
||||
features="{}",
|
||||
created_by="account-id",
|
||||
environment_variables=[],
|
||||
conversation_variables=[],
|
||||
rag_pipeline_variables=[],
|
||||
)
|
||||
workflow.id = "workflow-id"
|
||||
queue_manager = SimpleNamespace(publish=lambda event, pub_from: None)
|
||||
return _RecordingWorkflowAppRunner(
|
||||
application_generate_entity=app_entity,
|
||||
|
||||
@ -1,14 +1,32 @@
|
||||
from types import SimpleNamespace
|
||||
import json
|
||||
from unittest.mock import patch
|
||||
|
||||
from core.app.apps.workflow.app_config_manager import WorkflowAppConfigManager
|
||||
from models.model import AppMode
|
||||
from models.model import App, AppMode
|
||||
from models.workflow import Workflow, WorkflowType
|
||||
|
||||
|
||||
def _app() -> App:
|
||||
return App(id="app-1", tenant_id="tenant-1", name="Workflow App", mode=AppMode.WORKFLOW)
|
||||
|
||||
|
||||
def _workflow() -> Workflow:
|
||||
return Workflow(
|
||||
id="wf-1",
|
||||
tenant_id="tenant-1",
|
||||
app_id="app-1",
|
||||
type=WorkflowType.WORKFLOW,
|
||||
version=Workflow.VERSION_DRAFT,
|
||||
graph="{}",
|
||||
features=json.dumps({}),
|
||||
created_by="account-1",
|
||||
)
|
||||
|
||||
|
||||
class TestWorkflowAppConfigManager:
|
||||
def test_get_app_config(self):
|
||||
app_model = SimpleNamespace(id="app-1", tenant_id="tenant-1", mode=AppMode.WORKFLOW)
|
||||
workflow = SimpleNamespace(id="wf-1", features_dict={})
|
||||
app_model = _app()
|
||||
workflow = _workflow()
|
||||
|
||||
with (
|
||||
patch(
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import json
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
|
||||
from core.app.app_config.entities import WorkflowUIBasedAppConfig
|
||||
from core.app.apps.base_app_queue_manager import AppQueueManager
|
||||
from core.app.apps.workflow.generate_task_pipeline import WorkflowAppGenerateTaskPipeline
|
||||
@ -12,6 +14,7 @@ from graphon.entities import WorkflowStartReason
|
||||
from graphon.runtime import GraphRuntimeState
|
||||
from models.account import Account
|
||||
from models.model import AppMode
|
||||
from models.workflow import Workflow, WorkflowType
|
||||
from tests.workflow_test_utils import build_test_variable_pool
|
||||
|
||||
|
||||
@ -42,18 +45,20 @@ def _build_runtime_state(run_id: str) -> GraphRuntimeState:
|
||||
return GraphRuntimeState(variable_pool=variable_pool, start_at=time.perf_counter())
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _noop_session():
|
||||
yield MagicMock()
|
||||
|
||||
|
||||
def _build_pipeline(run_id: str) -> WorkflowAppGenerateTaskPipeline:
|
||||
def _build_pipeline(run_id: str, unbound_session_factory: sessionmaker[Session]) -> WorkflowAppGenerateTaskPipeline:
|
||||
queue_manager = MagicMock(spec=AppQueueManager)
|
||||
queue_manager.invoke_from = InvokeFrom.SERVICE_API
|
||||
queue_manager.graph_runtime_state = _build_runtime_state(run_id)
|
||||
workflow = MagicMock()
|
||||
workflow.id = "workflow-id"
|
||||
workflow.features_dict = {}
|
||||
workflow = Workflow(
|
||||
id="workflow-id",
|
||||
tenant_id="tenant-id",
|
||||
app_id="app-id",
|
||||
type=WorkflowType.WORKFLOW,
|
||||
version=Workflow.VERSION_DRAFT,
|
||||
graph="{}",
|
||||
features=json.dumps({}),
|
||||
created_by="user-id",
|
||||
)
|
||||
user = Account(name="user", email="user@example.com")
|
||||
pipeline = WorkflowAppGenerateTaskPipeline(
|
||||
application_generate_entity=_build_generate_entity(run_id),
|
||||
@ -63,13 +68,13 @@ def _build_pipeline(run_id: str) -> WorkflowAppGenerateTaskPipeline:
|
||||
stream=False,
|
||||
draft_var_saver_factory=MagicMock(),
|
||||
)
|
||||
pipeline._database_session = _noop_session
|
||||
pipeline._database_session = unbound_session_factory
|
||||
return pipeline
|
||||
|
||||
|
||||
def test_workflow_app_log_saved_only_on_initial_start() -> None:
|
||||
def test_workflow_app_log_saved_only_on_initial_start(unbound_session_factory: sessionmaker[Session]) -> None:
|
||||
run_id = "run-initial"
|
||||
pipeline = _build_pipeline(run_id)
|
||||
pipeline = _build_pipeline(run_id, unbound_session_factory)
|
||||
pipeline._save_workflow_app_log = MagicMock()
|
||||
|
||||
event = QueueWorkflowStartedEvent(reason=WorkflowStartReason.INITIAL)
|
||||
@ -81,9 +86,9 @@ def test_workflow_app_log_saved_only_on_initial_start() -> None:
|
||||
assert pipeline._workflow_execution_id == run_id
|
||||
|
||||
|
||||
def test_workflow_app_log_skipped_on_resumption_start() -> None:
|
||||
def test_workflow_app_log_skipped_on_resumption_start(unbound_session_factory: sessionmaker[Session]) -> None:
|
||||
run_id = "run-resume"
|
||||
pipeline = _build_pipeline(run_id)
|
||||
pipeline = _build_pipeline(run_id, unbound_session_factory)
|
||||
pipeline._save_workflow_app_log = MagicMock()
|
||||
|
||||
event = QueueWorkflowStartedEvent(reason=WorkflowStartReason.RESUMPTION)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from types import SimpleNamespace
|
||||
|
||||
@ -53,12 +54,35 @@ from graphon.enums import BuiltinNodeTypes, WorkflowExecutionStatus
|
||||
from graphon.model_runtime.entities.llm_entities import LLMUsage
|
||||
from graphon.runtime import GraphRuntimeState, VariablePool
|
||||
from libs.datetime_utils import naive_utc_now
|
||||
from models.enums import CreatorUserRole
|
||||
from models.enums import CreatorUserRole, EndUserType
|
||||
from models.model import AppMode, EndUser
|
||||
from models.workflow import WorkflowAppLog
|
||||
from models.workflow import Workflow, WorkflowAppLog, WorkflowType
|
||||
from tests.workflow_test_utils import build_test_variable_pool
|
||||
|
||||
|
||||
def _workflow() -> Workflow:
|
||||
return Workflow(
|
||||
id="workflow-id",
|
||||
tenant_id="tenant",
|
||||
app_id="app",
|
||||
type=WorkflowType.WORKFLOW,
|
||||
version=Workflow.VERSION_DRAFT,
|
||||
graph="{}",
|
||||
features=json.dumps({}),
|
||||
created_by="user",
|
||||
)
|
||||
|
||||
|
||||
def _end_user(*, end_user_id: str = "user", session_id: str = "session") -> EndUser:
|
||||
return EndUser(
|
||||
id=end_user_id,
|
||||
tenant_id="tenant",
|
||||
app_id="app",
|
||||
type=EndUserType.BROWSER,
|
||||
session_id=session_id,
|
||||
)
|
||||
|
||||
|
||||
def _make_pipeline():
|
||||
app_config = WorkflowUIBasedAppConfig(
|
||||
tenant_id="tenant",
|
||||
@ -81,8 +105,8 @@ def _make_pipeline():
|
||||
extras={},
|
||||
call_depth=0,
|
||||
)
|
||||
workflow = SimpleNamespace(id="workflow-id", tenant_id="tenant", features_dict={})
|
||||
user = SimpleNamespace(id="user", session_id="session")
|
||||
workflow = _workflow()
|
||||
user = _end_user()
|
||||
|
||||
pipeline = WorkflowAppGenerateTaskPipeline(
|
||||
application_generate_entity=application_generate_entity,
|
||||
@ -505,10 +529,9 @@ class TestWorkflowGenerateTaskPipeline:
|
||||
extras={},
|
||||
call_depth=0,
|
||||
)
|
||||
workflow = SimpleNamespace(id="workflow-id", tenant_id="tenant", features_dict={})
|
||||
workflow = _workflow()
|
||||
queue_manager = SimpleNamespace(invoke_from=InvokeFrom.WEB_APP, graph_runtime_state=None)
|
||||
end_user = EndUser(tenant_id="tenant", type="session", name="user", session_id="session-id")
|
||||
end_user.id = "end-user-id"
|
||||
end_user = _end_user(end_user_id="end-user-id", session_id="session-id")
|
||||
|
||||
pipeline = WorkflowAppGenerateTaskPipeline(
|
||||
application_generate_entity=application_generate_entity,
|
||||
|
||||
@ -10,11 +10,28 @@ from core.app.entities.app_invoke_entities import InvokeFrom
|
||||
from core.app.features.annotation_reply.annotation_reply import AnnotationReplyFeature
|
||||
from models.dataset import DatasetCollectionBinding
|
||||
from models.enums import CollectionBindingType, ConversationFromSource
|
||||
from models.model import AppAnnotationHitHistory, AppAnnotationSetting, MessageAnnotation
|
||||
from models.model import App, AppAnnotationHitHistory, AppAnnotationSetting, AppMode, Message, MessageAnnotation
|
||||
|
||||
TABLES = (AppAnnotationSetting, DatasetCollectionBinding, MessageAnnotation, AppAnnotationHitHistory)
|
||||
|
||||
|
||||
def _app() -> App:
|
||||
return App(
|
||||
id="app-1",
|
||||
tenant_id="tenant-1",
|
||||
name="Test App",
|
||||
description="",
|
||||
mode=AppMode.CHAT,
|
||||
enable_site=True,
|
||||
enable_api=True,
|
||||
max_active_requests=0,
|
||||
)
|
||||
|
||||
|
||||
def _message() -> Message:
|
||||
return Message(id="msg-1")
|
||||
|
||||
|
||||
def _persist_binding(session: Session) -> DatasetCollectionBinding:
|
||||
binding = DatasetCollectionBinding(
|
||||
provider_name="prov",
|
||||
@ -65,8 +82,8 @@ class TestAnnotationReplyFeature:
|
||||
_persist_setting(sqlite_session, app_id="other-app", collection_binding_id=binding.id)
|
||||
|
||||
result = AnnotationReplyFeature().query(
|
||||
app_record=SimpleNamespace(id="app-1", tenant_id="tenant-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_record=_app(),
|
||||
message=_message(),
|
||||
query="hi",
|
||||
user_id="user-1",
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
@ -79,8 +96,8 @@ class TestAnnotationReplyFeature:
|
||||
_persist_setting(sqlite_session, collection_binding_id="missing-binding")
|
||||
|
||||
result = AnnotationReplyFeature().query(
|
||||
app_record=SimpleNamespace(id="app-1", tenant_id="tenant-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_record=_app(),
|
||||
message=_message(),
|
||||
query="hi",
|
||||
user_id="user-1",
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
@ -101,8 +118,8 @@ class TestAnnotationReplyFeature:
|
||||
"core.app.features.annotation_reply.annotation_reply.Vector", return_value=vector_instance
|
||||
) as vector_cls:
|
||||
result = AnnotationReplyFeature().query(
|
||||
app_record=SimpleNamespace(id="app-1", tenant_id="tenant-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_record=_app(),
|
||||
message=_message(),
|
||||
query="hi",
|
||||
user_id="user-1",
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
@ -135,8 +152,8 @@ class TestAnnotationReplyFeature:
|
||||
|
||||
with patch("core.app.features.annotation_reply.annotation_reply.Vector", return_value=vector_instance):
|
||||
result = AnnotationReplyFeature().query(
|
||||
app_record=SimpleNamespace(id="app-1", tenant_id="tenant-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_record=_app(),
|
||||
message=_message(),
|
||||
query="hi",
|
||||
user_id="user-1",
|
||||
invoke_from=InvokeFrom.EXPLORE,
|
||||
@ -162,8 +179,8 @@ class TestAnnotationReplyFeature:
|
||||
caplog.at_level(logging.WARNING),
|
||||
):
|
||||
result = AnnotationReplyFeature().query(
|
||||
app_record=SimpleNamespace(id="app-1", tenant_id="tenant-1"),
|
||||
message=SimpleNamespace(id="msg-1"),
|
||||
app_record=_app(),
|
||||
message=_message(),
|
||||
query="hi",
|
||||
user_id="user-1",
|
||||
invoke_from=InvokeFrom.SERVICE_API,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
from collections.abc import Iterator
|
||||
from datetime import UTC, datetime
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
@ -31,7 +32,8 @@ from core.base.tts import AppGeneratorTTSPublisher
|
||||
from core.ops.ops_trace_manager import TraceQueueManager
|
||||
from graphon.model_runtime.entities.llm_entities import LLMResult as RuntimeLLMResult
|
||||
from graphon.model_runtime.entities.message_entities import TextPromptMessageContent
|
||||
from models.model import AppMode
|
||||
from models.enums import ConversationFromSource
|
||||
from models.model import AppMode, Conversation, Message
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -92,21 +94,25 @@ class TestEasyUIBasedGenerateTaskPipelineProcessStreamResponse:
|
||||
return manager
|
||||
|
||||
@pytest.fixture
|
||||
def mock_conversation(self):
|
||||
"""Create a mock conversation."""
|
||||
conversation = Mock()
|
||||
conversation.id = "test-conversation-id"
|
||||
conversation.mode = "chat"
|
||||
return conversation
|
||||
def conversation(self):
|
||||
"""Create a transient mapped conversation."""
|
||||
return Conversation(
|
||||
id="test-conversation-id",
|
||||
app_id="test-app-id",
|
||||
mode=AppMode.CHAT,
|
||||
name="Test Conversation",
|
||||
status="normal",
|
||||
from_source=ConversationFromSource.API,
|
||||
inputs={},
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def mock_message(self):
|
||||
"""Create a mock message."""
|
||||
message = Mock()
|
||||
message.id = "test-message-id"
|
||||
message.created_at = Mock()
|
||||
message.created_at.timestamp.return_value = 1234567890
|
||||
return message
|
||||
def message(self):
|
||||
"""Create a transient mapped message."""
|
||||
return Message(
|
||||
id="test-message-id",
|
||||
created_at=datetime.fromtimestamp(1234567890, tz=UTC),
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def mock_task_state(self):
|
||||
@ -129,8 +135,8 @@ class TestEasyUIBasedGenerateTaskPipelineProcessStreamResponse:
|
||||
self,
|
||||
mock_application_generate_entity,
|
||||
mock_queue_manager,
|
||||
mock_conversation,
|
||||
mock_message,
|
||||
conversation,
|
||||
message,
|
||||
mock_message_cycle_manager,
|
||||
mock_task_state,
|
||||
):
|
||||
@ -141,8 +147,8 @@ class TestEasyUIBasedGenerateTaskPipelineProcessStreamResponse:
|
||||
pipeline = EasyUIBasedGenerateTaskPipeline(
|
||||
application_generate_entity=mock_application_generate_entity,
|
||||
queue_manager=mock_queue_manager,
|
||||
conversation=mock_conversation,
|
||||
message=mock_message,
|
||||
conversation=conversation,
|
||||
message=message,
|
||||
stream=True,
|
||||
)
|
||||
pipeline._message_cycle_manager = mock_message_cycle_manager
|
||||
|
||||
@ -20,7 +20,7 @@ from graphon.file import FileTransferMethod, FileType
|
||||
from models import model as model_module
|
||||
from models.base import TypeBase
|
||||
from models.enums import ConversationFromSource, CreatorUserRole, MessageFileBelongsTo
|
||||
from models.model import App, AppMode, Conversation, MessageFile
|
||||
from models.model import App, AppMode, Conversation, MessageAnnotation, MessageFile
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -426,10 +426,13 @@ class TestMessageCycleManagerOptimization:
|
||||
"""
|
||||
message_cycle_manager._task_state = SimpleNamespace(metadata=TaskStateMetadata())
|
||||
|
||||
annotation = SimpleNamespace(
|
||||
id="ann-1",
|
||||
annotation = MessageAnnotation(
|
||||
app_id="app-id",
|
||||
question="question",
|
||||
content="answer",
|
||||
account_id="acct-1",
|
||||
)
|
||||
annotation.id = "ann-1"
|
||||
session = unbound_session
|
||||
|
||||
with (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user