refactor(core): decouple actors and remove workflow templates (#67)
Removes the deprecated `workflow_template` concept entirely across both backend API routers, internal logic handling within the `supervisory_node` and `consciousness_node`, and front-end components. Enables `consciousness_node` to work autonomously. Also refactors core package structure to enforce the "one python package, one Ray Actor" architectural rule. `GlobalWorkflowManager`, `WorkflowRunningEngine`, `PostgresDatabase`, and `WorkerCluster` have been moved to their own top-level decoupled package directories with properly exported `__init__.py` modules. Test suites have been relocated and import paths updated across the system. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: zhaoxi826 <198742034+zhaoxi826@users.noreply.github.com>
This commit is contained in:
@@ -7,14 +7,16 @@ real_import = builtins.__import__
|
||||
|
||||
|
||||
def mock_import(name, globals=None, locals=None, fromlist=(), level=0):
|
||||
if name == 'ray':
|
||||
if name == "ray":
|
||||
mock_ray = MagicMock()
|
||||
|
||||
def mock_remote(*args, **kwargs):
|
||||
if len(args) == 1 and callable(args[0]):
|
||||
return args[0]
|
||||
|
||||
def decorator(cls):
|
||||
return cls
|
||||
|
||||
return decorator
|
||||
|
||||
mock_ray.remote = mock_remote
|
||||
@@ -25,10 +27,10 @@ def mock_import(name, globals=None, locals=None, fromlist=(), level=0):
|
||||
builtins.__import__ = mock_import
|
||||
|
||||
for mod in list(sys.modules.keys()):
|
||||
if 'pretor.core.global_state_machine.global_state_machine' in mod or 'ray' in mod:
|
||||
if "pretor.core.global_state_machine.global_state_machine" in mod or "ray" in mod:
|
||||
del sys.modules[mod]
|
||||
|
||||
from pretor.core.global_state_machine.global_state_machine import GlobalStateMachine
|
||||
from pretor.core.global_state_machine.global_state_machine import GlobalStateMachine # noqa: E402
|
||||
|
||||
builtins.__import__ = real_import
|
||||
|
||||
@@ -82,13 +84,17 @@ async def test_add_provider_unsupported(gsm):
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_provider_request_error(gsm):
|
||||
from httpx import RequestError
|
||||
|
||||
mock_provider_class = AsyncMock()
|
||||
mock_provider_class.create_provider.side_effect = RequestError("Network Error", request=MagicMock())
|
||||
mock_provider_class.create_provider.side_effect = RequestError(
|
||||
"Network Error", request=MagicMock()
|
||||
)
|
||||
gsm._global_provider_manager.provider_mapper = {"openai": mock_provider_class}
|
||||
|
||||
with patch("pretor.utils.logger.global_logger.bind") as mock_bind:
|
||||
from pretor.utils.error import RetryableError
|
||||
import pytest
|
||||
|
||||
mock_logger = MagicMock()
|
||||
mock_bind.return_value = mock_logger
|
||||
with pytest.raises(RetryableError):
|
||||
@@ -117,3 +123,4 @@ def test_get_provider_list_and_get_provider(gsm):
|
||||
assert gsm._global_provider_manager.get_provider_list() == {"p1": mock_provider}
|
||||
assert gsm._global_provider_manager.get_provider("p1") == mock_provider
|
||||
assert gsm._global_provider_manager.get_provider("missing") is None
|
||||
# noqa: E402
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
from pretor.core.global_state_machine.model_provider.base_provider import Provider, ProviderArgs, ProviderStatus
|
||||
from pretor.core.global_state_machine.model_provider.base_provider import (
|
||||
Provider,
|
||||
ProviderArgs,
|
||||
ProviderStatus,
|
||||
)
|
||||
|
||||
|
||||
def test_provider_status():
|
||||
assert ProviderStatus.UP == "up"
|
||||
assert ProviderStatus.DOWN == "down"
|
||||
|
||||
|
||||
def test_provider_args():
|
||||
args = ProviderArgs(
|
||||
provider_title="title",
|
||||
provider_url="url",
|
||||
provider_apikey="key",
|
||||
provider_owner="1"
|
||||
provider_owner="1",
|
||||
)
|
||||
assert args.provider_title == "title"
|
||||
|
||||
|
||||
def test_provider_model():
|
||||
p = Provider(
|
||||
provider_title="title",
|
||||
provider_url="url",
|
||||
provider_apikey="key",
|
||||
provider_models=["model"],
|
||||
provider_type="openai"
|
||||
provider_type="openai",
|
||||
)
|
||||
assert p.provider_status == ProviderStatus.UP
|
||||
assert p.provider_owner is None
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import pytest
|
||||
from unittest.mock import patch, MagicMock, AsyncMock
|
||||
from pretor.core.global_state_machine.model_provider.claude_provider import ClaudeProvider, ProviderArgs
|
||||
from pretor.core.global_state_machine.model_provider.claude_provider import (
|
||||
ClaudeProvider,
|
||||
ProviderArgs,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -9,12 +12,14 @@ def provider_args():
|
||||
provider_title="TestClaude",
|
||||
provider_url="https://api.anthropic.com",
|
||||
provider_apikey="testkey",
|
||||
provider_owner="1"
|
||||
provider_owner="1",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.claude_provider.httpx.AsyncClient")
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.claude_provider.httpx.AsyncClient"
|
||||
)
|
||||
async def test_load_models_success(mock_client, provider_args):
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
@@ -31,7 +36,9 @@ async def test_load_models_success(mock_client, provider_args):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.claude_provider.httpx.AsyncClient")
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.claude_provider.httpx.AsyncClient"
|
||||
)
|
||||
async def test_load_models_error(mock_client, provider_args):
|
||||
mock_client_instance = AsyncMock()
|
||||
mock_client_instance.get.side_effect = Exception("network error")
|
||||
@@ -42,8 +49,10 @@ async def test_load_models_error(mock_client, provider_args):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.claude_provider.ClaudeProvider._load_models",
|
||||
return_value=["claude-3"])
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.claude_provider.ClaudeProvider._load_models",
|
||||
return_value=["claude-3"],
|
||||
)
|
||||
async def test_create_provider(mock_load, provider_args):
|
||||
provider = await ClaudeProvider.create_provider(provider_args)
|
||||
assert provider.provider_title == "TestClaude"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import pytest
|
||||
from unittest.mock import patch, MagicMock, AsyncMock
|
||||
from pretor.core.global_state_machine.model_provider.openai_provider import OpenAIProvider, ProviderArgs
|
||||
from pretor.core.global_state_machine.model_provider.openai_provider import (
|
||||
OpenAIProvider,
|
||||
ProviderArgs,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -9,7 +12,7 @@ def provider_args():
|
||||
provider_title="TestOpenAI",
|
||||
provider_url="https://api.openai.com/v1",
|
||||
provider_apikey="testkey",
|
||||
provider_owner="1"
|
||||
provider_owner="1",
|
||||
)
|
||||
|
||||
|
||||
@@ -19,12 +22,14 @@ def provider_args_no_v1():
|
||||
provider_title="TestOpenAI",
|
||||
provider_url="https://api.openai.com",
|
||||
provider_apikey="testkey",
|
||||
provider_owner="1"
|
||||
provider_owner="1",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient")
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient"
|
||||
)
|
||||
async def test_load_models_success(mock_client, provider_args):
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
@@ -40,12 +45,14 @@ async def test_load_models_success(mock_client, provider_args):
|
||||
assert models == ["gpt-3.5-turbo", "gpt-4"]
|
||||
mock_client_instance.get.assert_called_once_with(
|
||||
"https://api.openai.com/v1/models",
|
||||
headers={"Authorization": "Bearer testkey", "Content-Type": "application/json"}
|
||||
headers={"Authorization": "Bearer testkey", "Content-Type": "application/json"},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient")
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient"
|
||||
)
|
||||
async def test_load_models_no_v1(mock_client, provider_args_no_v1):
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
@@ -59,12 +66,14 @@ async def test_load_models_no_v1(mock_client, provider_args_no_v1):
|
||||
assert models == []
|
||||
mock_client_instance.get.assert_called_once_with(
|
||||
"https://api.openai.com/v1/models",
|
||||
headers={"Authorization": "Bearer testkey", "Content-Type": "application/json"}
|
||||
headers={"Authorization": "Bearer testkey", "Content-Type": "application/json"},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient")
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient"
|
||||
)
|
||||
async def test_load_models_status_error(mock_client, provider_args):
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 401
|
||||
@@ -78,21 +87,29 @@ async def test_load_models_status_error(mock_client, provider_args):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient")
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient"
|
||||
)
|
||||
async def test_load_models_request_error(mock_client, provider_args):
|
||||
import httpx
|
||||
|
||||
mock_client_instance = AsyncMock()
|
||||
mock_client_instance.get.side_effect = httpx.RequestError("network error", request=MagicMock())
|
||||
mock_client_instance.get.side_effect = httpx.RequestError(
|
||||
"network error", request=MagicMock()
|
||||
)
|
||||
mock_client.return_value.__aenter__.return_value = mock_client_instance
|
||||
|
||||
import pytest
|
||||
from pretor.utils.error import RetryableError
|
||||
|
||||
with pytest.raises(RetryableError):
|
||||
await OpenAIProvider._load_models(provider_args)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient")
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.openai_provider.httpx.AsyncClient"
|
||||
)
|
||||
async def test_load_models_generic_error(mock_client, provider_args):
|
||||
mock_client_instance = AsyncMock()
|
||||
mock_client_instance.get.side_effect = Exception("generic error")
|
||||
@@ -103,8 +120,10 @@ async def test_load_models_generic_error(mock_client, provider_args):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("pretor.core.global_state_machine.model_provider.openai_provider.OpenAIProvider._load_models",
|
||||
return_value=["gpt-4"])
|
||||
@patch(
|
||||
"pretor.core.global_state_machine.model_provider.openai_provider.OpenAIProvider._load_models",
|
||||
return_value=["gpt-4"],
|
||||
)
|
||||
async def test_create_provider(mock_load, provider_args):
|
||||
provider = await OpenAIProvider.create_provider(provider_args)
|
||||
assert provider.provider_title == "TestOpenAI"
|
||||
|
||||
@@ -13,11 +13,15 @@ async def test_provider_manager_init():
|
||||
mock_provider2.provider_title = "title2"
|
||||
|
||||
mock_postgres.get_provider = MagicMock()
|
||||
mock_postgres.get_provider.remote = AsyncMock(return_value=[mock_provider1, mock_provider2])
|
||||
mock_postgres.get_provider.remote = AsyncMock(
|
||||
return_value=[mock_provider1, mock_provider2]
|
||||
)
|
||||
|
||||
manager = ProviderManager(mock_postgres)
|
||||
mock_postgres.provider_database = MagicMock()
|
||||
mock_postgres.provider_database.remote = AsyncMock(return_value=[mock_provider1, mock_provider2])
|
||||
mock_postgres.provider_database.remote = AsyncMock(
|
||||
return_value=[mock_provider1, mock_provider2]
|
||||
)
|
||||
await manager.init_provider_register(mock_postgres)
|
||||
|
||||
assert "openai" in manager.provider_mapper
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from pretor.core.global_state_machine.tool_manager import GlobalToolManager
|
||||
|
||||
|
||||
def test_global_tool_manager_init():
|
||||
manager = GlobalToolManager()
|
||||
assert isinstance(manager, GlobalToolManager)
|
||||
|
||||
Reference in New Issue
Block a user