diff --git a/pyproject.toml b/pyproject.toml index c10bfb4..49182f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,11 +36,6 @@ dev = [ [tool.coverage.run] source = ["src/mitocode"] -omit = [ - "src/mitocode/tui/*", - "src/mitocode/__main__.py", - "src/mitocode/backend/chat_provider/scenario_provider.py", -] [tool.pyright] typeCheckingMode = "standard" diff --git a/src/mitocode/__init__.py b/src/mitocode/__init__.py index 43f0c93..352ad9b 100644 --- a/src/mitocode/__init__.py +++ b/src/mitocode/__init__.py @@ -3,7 +3,7 @@ APP_VERSION = 2 MITOCODE_CONFIG_PATH = ".mitocode" -from mitocode.backend.agent import SessionFactory, AgentOrchestrator +from mitocode.core.agent import SessionFactory, AgentOrchestrator __all__ = [ "APP_VERSION", diff --git a/src/mitocode/__main__.py b/src/mitocode/__main__.py index f511246..4b0e1ee 100644 --- a/src/mitocode/__main__.py +++ b/src/mitocode/__main__.py @@ -6,10 +6,10 @@ from httpx import stream -from mitocode.backend.agent.agent_orchestrator import AgentOrchestrator -from mitocode.backend.chat_provider.scenario_provider import ScenarioProvider -from mitocode.backend.chat_provider.chat_provider_openai import ChatProviderOpenAI -from mitocode.backend.tool.tool_manager import ToolManager +from mitocode.core.agent.agent_orchestrator import AgentOrchestrator +from mitocode.core.chat_provider.scenario_provider import ScenarioProvider +from mitocode.core.chat_provider.chat_provider_openai import ChatProviderOpenAI +from mitocode.core.tool.tool_manager import ToolManager from mitocode.tui.ui_main import VibeFrontend diff --git a/src/mitocode/backend/__init__.py b/src/mitocode/core/__init__.py similarity index 82% rename from src/mitocode/backend/__init__.py rename to src/mitocode/core/__init__.py index 192cfe6..5ee61ae 100644 --- a/src/mitocode/backend/__init__.py +++ b/src/mitocode/core/__init__.py @@ -1,6 +1,6 @@ """Backend layer for MitoCode""" -from mitocode.backend.agent import ( +from mitocode.core.agent import ( AgentNode, AgentOrchestrator, AgentRuntime, @@ -11,7 +11,7 @@ ToolSpec, declare_tool, ) -from mitocode.backend.bridge import EventBridge +from mitocode.core.bridge import EventBridge __all__ = [ "AgentNode", diff --git a/src/mitocode/backend/agent/__init__.py b/src/mitocode/core/agent/__init__.py similarity index 90% rename from src/mitocode/backend/agent/__init__.py rename to src/mitocode/core/agent/__init__.py index f3f54db..bfe70ed 100644 --- a/src/mitocode/backend/agent/__init__.py +++ b/src/mitocode/core/agent/__init__.py @@ -4,7 +4,7 @@ and the session factory used to build agent sessions. """ -from mitocode.backend.tool.tool_manager import ToolManager, ToolSpec, declare_tool +from mitocode.core.tool.tool_manager import ToolManager, ToolSpec, declare_tool from .agent_node import AgentNode from .agent_orchestrator import AgentOrchestrator from .agent_runtime import AgentRuntime diff --git a/src/mitocode/backend/agent/agent_node.py b/src/mitocode/core/agent/agent_node.py similarity index 100% rename from src/mitocode/backend/agent/agent_node.py rename to src/mitocode/core/agent/agent_node.py diff --git a/src/mitocode/backend/agent/agent_orchestrator.py b/src/mitocode/core/agent/agent_orchestrator.py similarity index 100% rename from src/mitocode/backend/agent/agent_orchestrator.py rename to src/mitocode/core/agent/agent_orchestrator.py diff --git a/src/mitocode/backend/agent/agent_runtime.py b/src/mitocode/core/agent/agent_runtime.py similarity index 100% rename from src/mitocode/backend/agent/agent_runtime.py rename to src/mitocode/core/agent/agent_runtime.py diff --git a/src/mitocode/backend/agent/agent_session.py b/src/mitocode/core/agent/agent_session.py similarity index 99% rename from src/mitocode/backend/agent/agent_session.py rename to src/mitocode/core/agent/agent_session.py index d2d080e..64df605 100644 --- a/src/mitocode/backend/agent/agent_session.py +++ b/src/mitocode/core/agent/agent_session.py @@ -6,7 +6,7 @@ from loguru import logger as loguru_logger -from mitocode.backend.tool.tool_manager import ToolManager +from mitocode.core.tool.tool_manager import ToolManager from .agent_node import AgentNode from .agent_state import AgentState diff --git a/src/mitocode/backend/agent/agent_state.py b/src/mitocode/core/agent/agent_state.py similarity index 100% rename from src/mitocode/backend/agent/agent_state.py rename to src/mitocode/core/agent/agent_state.py diff --git a/src/mitocode/backend/agent/session_factory.py b/src/mitocode/core/agent/session_factory.py similarity index 100% rename from src/mitocode/backend/agent/session_factory.py rename to src/mitocode/core/agent/session_factory.py diff --git a/src/mitocode/backend/bridge/__init__.py b/src/mitocode/core/bridge/__init__.py similarity index 100% rename from src/mitocode/backend/bridge/__init__.py rename to src/mitocode/core/bridge/__init__.py diff --git a/src/mitocode/backend/bridge/event_adapter.py b/src/mitocode/core/bridge/event_adapter.py similarity index 100% rename from src/mitocode/backend/bridge/event_adapter.py rename to src/mitocode/core/bridge/event_adapter.py diff --git a/src/mitocode/backend/chat_provider/__init__.py b/src/mitocode/core/chat_provider/__init__.py similarity index 100% rename from src/mitocode/backend/chat_provider/__init__.py rename to src/mitocode/core/chat_provider/__init__.py diff --git a/src/mitocode/backend/chat_provider/chat_provider_openai.py b/src/mitocode/core/chat_provider/chat_provider_openai.py similarity index 99% rename from src/mitocode/backend/chat_provider/chat_provider_openai.py rename to src/mitocode/core/chat_provider/chat_provider_openai.py index c2a19df..a90d446 100644 --- a/src/mitocode/backend/chat_provider/chat_provider_openai.py +++ b/src/mitocode/core/chat_provider/chat_provider_openai.py @@ -6,7 +6,7 @@ from openai.pagination import AsyncPage from openai.types import Model -from mitocode.backend.exception.mitocode_exception import ( +from mitocode.core.exception.mitocode_exception import ( MitoCodeChatProviderModelError, ) from .sample_chat_provider import _SampleChatProvider diff --git a/src/mitocode/backend/chat_provider/sample_chat_provider.py b/src/mitocode/core/chat_provider/sample_chat_provider.py similarity index 98% rename from src/mitocode/backend/chat_provider/sample_chat_provider.py rename to src/mitocode/core/chat_provider/sample_chat_provider.py index 61db2c3..ba0b420 100644 --- a/src/mitocode/backend/chat_provider/sample_chat_provider.py +++ b/src/mitocode/core/chat_provider/sample_chat_provider.py @@ -7,7 +7,7 @@ from abc import abstractmethod, ABC from typing import List, Dict, Optional, Any, AsyncGenerator -from mitocode.backend.exception.mitocode_exception import ( +from mitocode.core.exception.mitocode_exception import ( MitoCodeChatProviderConfigError, ) diff --git a/src/mitocode/backend/chat_provider/scenario_provider.py b/src/mitocode/core/chat_provider/scenario_provider.py similarity index 99% rename from src/mitocode/backend/chat_provider/scenario_provider.py rename to src/mitocode/core/chat_provider/scenario_provider.py index fdb0804..c555503 100644 --- a/src/mitocode/backend/chat_provider/scenario_provider.py +++ b/src/mitocode/core/chat_provider/scenario_provider.py @@ -9,7 +9,7 @@ from types import SimpleNamespace from typing import Any, Dict, List, Optional, AsyncGenerator -from mitocode.backend.chat_provider.sample_chat_provider import _SampleChatProvider +from mitocode.core.chat_provider.sample_chat_provider import _SampleChatProvider def _make_chunk( diff --git a/src/mitocode/backend/exception/__init__.py b/src/mitocode/core/exception/__init__.py similarity index 100% rename from src/mitocode/backend/exception/__init__.py rename to src/mitocode/core/exception/__init__.py diff --git a/src/mitocode/backend/exception/mitocode_exception.py b/src/mitocode/core/exception/mitocode_exception.py similarity index 97% rename from src/mitocode/backend/exception/mitocode_exception.py rename to src/mitocode/core/exception/mitocode_exception.py index 6764637..ba21dec 100644 --- a/src/mitocode/backend/exception/mitocode_exception.py +++ b/src/mitocode/core/exception/mitocode_exception.py @@ -88,7 +88,7 @@ class MitoCodeMcpConnectionError(MitoCodeMcpError): """Reserved for when an MCP connection cannot be established or is lost. Nothing raises it yet, and that is deliberate rather than an oversight: - :class:`~mitocode.backend.mcp.mcp_client.McpClient` records a failed + :class:`~mitocode.core.mcp.mcp_client.McpClient` records a failed connection in ``state``/``last_error`` and returns ``False``, because one unreachable server must not abort the startup of the servers that work. Turning that into an exception belongs to whichever layer turns connection diff --git a/src/mitocode/backend/mcp/__init__.py b/src/mitocode/core/mcp/__init__.py similarity index 100% rename from src/mitocode/backend/mcp/__init__.py rename to src/mitocode/core/mcp/__init__.py diff --git a/src/mitocode/backend/mcp/mcp_client.py b/src/mitocode/core/mcp/mcp_client.py similarity index 98% rename from src/mitocode/backend/mcp/mcp_client.py rename to src/mitocode/core/mcp/mcp_client.py index 79063c2..7ee4b3e 100644 --- a/src/mitocode/backend/mcp/mcp_client.py +++ b/src/mitocode/core/mcp/mcp_client.py @@ -25,8 +25,8 @@ from fastmcp import Client from fastmcp.exceptions import ToolError -from mitocode.backend.exception.mitocode_exception import MitoCodeMcpToolCallError -from mitocode.backend.mcp.mcp_config import McpServerConfig +from mitocode.core.exception.mitocode_exception import MitoCodeMcpToolCallError +from mitocode.core.mcp.mcp_config import McpServerConfig #: Stands in for an argument payload that has been cut out of error text. _REDACTED = "" @@ -113,7 +113,7 @@ def _scrub_endpoint(text: str) -> str: A remote MCP endpoint may legitimately carry a secret in its userinfo, its query string or its fragment — ``?access_token=…`` is common enough that - :class:`~mitocode.backend.mcp.mcp_config.McpServerConfig` has to accept it + :class:`~mitocode.core.mcp.mcp_config.McpServerConfig` has to accept it — and a handshake failure routinely quotes the endpoint it was made against, in text that reaches the TUI error pane and the log. The MCP SDK strips the same parts from the URLs *it* builds, but nothing strips them diff --git a/src/mitocode/backend/mcp/mcp_config.py b/src/mitocode/core/mcp/mcp_config.py similarity index 99% rename from src/mitocode/backend/mcp/mcp_config.py rename to src/mitocode/core/mcp/mcp_config.py index dc29920..0a004d5 100644 --- a/src/mitocode/backend/mcp/mcp_config.py +++ b/src/mitocode/core/mcp/mcp_config.py @@ -14,7 +14,7 @@ from enum import Enum from typing import Any, Dict, List, NoReturn -from mitocode.backend.exception.mitocode_exception import MitoCodeMcpConfigError +from mitocode.core.exception.mitocode_exception import MitoCodeMcpConfigError try: from fastmcp.client.transports import ( diff --git a/src/mitocode/backend/mcp/mcp_manager.py b/src/mitocode/core/mcp/mcp_manager.py similarity index 97% rename from src/mitocode/backend/mcp/mcp_manager.py rename to src/mitocode/core/mcp/mcp_manager.py index 6f84926..cc4bd23 100644 --- a/src/mitocode/backend/mcp/mcp_manager.py +++ b/src/mitocode/core/mcp/mcp_manager.py @@ -1,6 +1,6 @@ """Lifecycle management for the set of configured MCP servers. -:class:`McpManager` owns one :class:`~mitocode.backend.mcp.mcp_client.McpClient` +:class:`McpManager` owns one :class:`~mitocode.core.mcp.mcp_client.McpClient` per configured server and decides when each of them starts, refreshes and stops. It takes no interest in what those tools look like: registration is delegated to :meth:`ToolManager.register_mcp_client`, which namespaces each @@ -33,18 +33,18 @@ from loguru import logger as loguru_logger -from mitocode.backend.exception.mitocode_exception import MitoCodeMcpConfigError -from mitocode.backend.mcp.mcp_client import McpClient, _scrub_endpoint -from mitocode.backend.mcp.mcp_config import McpServerConfig +from mitocode.core.exception.mitocode_exception import MitoCodeMcpConfigError +from mitocode.core.mcp.mcp_client import McpClient, _scrub_endpoint +from mitocode.core.mcp.mcp_config import McpServerConfig if TYPE_CHECKING: # The tool layer is reached only through the object handed in, never by # importing it: the dependency runs one way, tool_manager -> mcp. A runtime - # import here would make mitocode.backend.mcp unimportable on its own and + # import here would make mitocode.core.mcp unimportable on its own and # would break the symmetry with tool_manager's own TYPE_CHECKING guard for # McpClient. The annotation is quoted because this module has no # `from __future__ import annotations`, so annotations are evaluated. - from mitocode.backend.tool.tool_manager import ToolManager + from mitocode.core.tool.tool_manager import ToolManager logger = loguru_logger.bind(name=__name__) @@ -185,8 +185,8 @@ def __init__( The tool registry is held as a duck-typed object: the module never imports the tool layer, so any object exposing - :meth:`~mitocode.backend.tool.tool_manager.ToolManager.register_mcp_client` - and :meth:`~mitocode.backend.tool.tool_manager.ToolManager.unregister` + :meth:`~mitocode.core.tool.tool_manager.ToolManager.register_mcp_client` + and :meth:`~mitocode.core.tool.tool_manager.ToolManager.unregister` will do. Args: diff --git a/src/mitocode/backend/tool/__init__.py b/src/mitocode/core/tool/__init__.py similarity index 100% rename from src/mitocode/backend/tool/__init__.py rename to src/mitocode/core/tool/__init__.py diff --git a/src/mitocode/backend/tool/tool_manager.py b/src/mitocode/core/tool/tool_manager.py similarity index 99% rename from src/mitocode/backend/tool/tool_manager.py rename to src/mitocode/core/tool/tool_manager.py index 3d39ff5..fb651ab 100644 --- a/src/mitocode/backend/tool/tool_manager.py +++ b/src/mitocode/core/tool/tool_manager.py @@ -34,12 +34,12 @@ types = None UnionType = Union -from mitocode.backend.exception.mitocode_exception import MitoCodeToolDefinitionError +from mitocode.core.exception.mitocode_exception import MitoCodeToolDefinitionError if TYPE_CHECKING: # Imported for type checking only. The runtime stays on duck typing so # this module keeps importing in an environment without fastmcp installed. - from mitocode.backend.mcp.mcp_client import McpClient + from mitocode.core.mcp.mcp_client import McpClient logger = loguru_logger.bind(name=__name__) diff --git a/src/mitocode/backend/workspace/__init__.py b/src/mitocode/core/workspace/__init__.py similarity index 100% rename from src/mitocode/backend/workspace/__init__.py rename to src/mitocode/core/workspace/__init__.py diff --git a/src/mitocode/backend/workspace/config_schema.json b/src/mitocode/core/workspace/config_schema.json similarity index 100% rename from src/mitocode/backend/workspace/config_schema.json rename to src/mitocode/core/workspace/config_schema.json diff --git a/src/mitocode/backend/workspace/migration.py b/src/mitocode/core/workspace/migration.py similarity index 98% rename from src/mitocode/backend/workspace/migration.py rename to src/mitocode/core/workspace/migration.py index 53044bc..ca601dd 100644 --- a/src/mitocode/backend/workspace/migration.py +++ b/src/mitocode/core/workspace/migration.py @@ -5,7 +5,7 @@ from pathlib import Path from typing import Union, Callable, Awaitable from mitocode import APP_VERSION, MITOCODE_CONFIG_PATH -from mitocode.backend.exception.mitocode_exception import ( +from mitocode.core.exception.mitocode_exception import ( MitoCodeWorkspaceInitError, MitoCodePathConvertError, MitoCodeMigrateError, diff --git a/src/mitocode/backend/workspace/snapshot.py b/src/mitocode/core/workspace/snapshot.py similarity index 100% rename from src/mitocode/backend/workspace/snapshot.py rename to src/mitocode/core/workspace/snapshot.py diff --git a/src/mitocode/backend/workspace/workspace.py b/src/mitocode/core/workspace/workspace.py similarity index 99% rename from src/mitocode/backend/workspace/workspace.py rename to src/mitocode/core/workspace/workspace.py index 6165614..5948d51 100644 --- a/src/mitocode/backend/workspace/workspace.py +++ b/src/mitocode/core/workspace/workspace.py @@ -7,7 +7,7 @@ from typing import Union, Awaitable from mitocode import MITOCODE_CONFIG_PATH, APP_VERSION -from mitocode.backend.exception.mitocode_exception import ( +from mitocode.core.exception.mitocode_exception import ( MitoCodePathConvertError, MitoCodeWorkspaceInitError, MitoCodeWorkspaceDumpError, diff --git a/src/mitocode/tui/ui_main.py b/src/mitocode/tui/ui_main.py index 3a02142..f5e9ce7 100644 --- a/src/mitocode/tui/ui_main.py +++ b/src/mitocode/tui/ui_main.py @@ -16,7 +16,7 @@ from textual.widgets import Tree from textual.widgets._tree import TreeNode -from mitocode.backend.agent.agent_orchestrator import AgentOrchestrator +from mitocode.core.agent.agent_orchestrator import AgentOrchestrator STATUS_ICONS = { "idle": "\u26aa", diff --git a/test/test_agent_runtime.py b/test/test_agent_runtime.py index 9a4e3f5..b2b0e52 100644 --- a/test/test_agent_runtime.py +++ b/test/test_agent_runtime.py @@ -1,6 +1,6 @@ """AgentRuntime 模块单元测试套件。 -覆盖 src/mitocode/backend/agent/agent_runtime.py 的全部行为分支: +覆盖 src/mitocode/core/agent/agent_runtime.py 的全部行为分支: _invoke_tool / _invoke_on_end 的协程与线程分发规则、run() 主循环的 文本流式事件、按 index 聚合并行工具调用、分片 id/name 同步、 工具执行五分支(解析失败/未注册/TypeError/异常/成功)、on_end 回调时序、 @@ -18,9 +18,9 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) -from mitocode.backend.agent.agent_runtime import AgentRuntime -from mitocode.backend.agent.agent_session import AgentSession -from mitocode.backend.chat_provider.sample_chat_provider import _SampleChatProvider +from mitocode.core.agent.agent_runtime import AgentRuntime +from mitocode.core.agent.agent_session import AgentSession +from mitocode.core.chat_provider.sample_chat_provider import _SampleChatProvider # ────────────────────────────────────────────── # 常量 diff --git a/test/test_agent_session.py b/test/test_agent_session.py index 1476945..5d16b11 100644 --- a/test/test_agent_session.py +++ b/test/test_agent_session.py @@ -1,6 +1,6 @@ """AgentSession 模块单元测试套件。 -覆盖 src/mitocode/backend/agent/agent_session.py 的全部行为分支: +覆盖 src/mitocode/core/agent/agent_session.py 的全部行为分支: 消息块三兄弟(文本/工具调用/工具结果)的构造与转换、AgentSession 构造校验、 托管/用户工具合并规则、文档查询委托、协作式取消、流式增量聚合、 标准上下文编译以及 TUI 节点快照映射。 @@ -14,16 +14,16 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) -from mitocode.backend.agent.agent_session import ( +from mitocode.core.agent.agent_session import ( AgentSession, _MessageBlock, _PlainTextMessageBlock, _ToolCallMessageBlock, _ToolResultMessageBlock, ) -from mitocode.backend.agent.agent_state import AgentState -from mitocode.backend.chat_provider.sample_chat_provider import _SampleChatProvider -from mitocode.backend.tool.tool_manager import ToolManager +from mitocode.core.agent.agent_state import AgentState +from mitocode.core.chat_provider.sample_chat_provider import _SampleChatProvider +from mitocode.core.tool.tool_manager import ToolManager TOOL_NAME_WEATHER = "get_weather" CALL_ID_PRIMARY = "call_001" @@ -31,7 +31,7 @@ VALID_JSON_ARGS = '{"city": "Beijing"}' INVALID_JSON_ARGS = "{这不是JSON" LIST_JSON_ARGS = "[1, 2]" -LOGGER_PATCH_TARGET = "mitocode.backend.agent.agent_session.logger" +LOGGER_PATCH_TARGET = "mitocode.core.agent.agent_session.logger" # ────────────────────────────────────────────── diff --git a/test/test_mcp_client.py b/test/test_mcp_client.py index 6b9c20a..99497d3 100644 --- a/test/test_mcp_client.py +++ b/test/test_mcp_client.py @@ -13,14 +13,14 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) -from mitocode.backend.exception.mitocode_exception import MitoCodeMcpToolCallError -from mitocode.backend.mcp.mcp_client import ( +from mitocode.core.exception.mitocode_exception import MitoCodeMcpToolCallError +from mitocode.core.mcp.mcp_client import ( McpClient, McpConnectionState, _redact_arguments, _scrub_endpoint, ) -from mitocode.backend.mcp.mcp_config import McpServerConfig +from mitocode.core.mcp.mcp_config import McpServerConfig def _server() -> FastMCP: @@ -323,7 +323,7 @@ async def test_connect_failure_never_echoes_a_credential_in_the_endpoint(): ``McpServerConfig`` deliberately permits ``?access_token=…``, and a server or proxy that fails the handshake routinely quotes the endpoint it was called on — including its query string. That text ends up in ``last_error``, - which :meth:`~mitocode.backend.mcp.mcp_manager.McpManager.status` publishes + which :meth:`~mitocode.core.mcp.mcp_manager.McpManager.status` publishes verbatim and the TUI pane an operator reads. The scrubbing is therefore pinned against a *real* transport, not a hand-written exception: the assertion has to survive whatever the MCP SDK chooses to put in the message. diff --git a/test/test_mcp_config.py b/test/test_mcp_config.py index ed750a0..e1898cd 100644 --- a/test/test_mcp_config.py +++ b/test/test_mcp_config.py @@ -1,4 +1,4 @@ -"""Unit tests for :mod:`mitocode.backend.mcp.mcp_config`. +"""Unit tests for :mod:`mitocode.core.mcp.mcp_config`. The module is pure: it normalises a ``{"mcpServers": {...}}`` document into frozen :class:`McpServerConfig` values and assembles a fastmcp transport @@ -63,9 +63,9 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) -from mitocode.backend.exception.mitocode_exception import MitoCodeMcpConfigError -from mitocode.backend.mcp import mcp_config -from mitocode.backend.mcp.mcp_config import McpServerConfig, McpServerKind +from mitocode.core.exception.mitocode_exception import MitoCodeMcpConfigError +from mitocode.core.mcp import mcp_config +from mitocode.core.mcp.mcp_config import McpServerConfig, McpServerKind # A valid https endpoint used wherever the transport selector is incidental. HTTP_ENDPOINT = "https://weather.example.com/mcp" @@ -79,7 +79,7 @@ def test_mcp_config_error_is_a_mitocode_base_error(): - from mitocode.backend.exception.mitocode_exception import MitoCodeMcpError + from mitocode.core.exception.mitocode_exception import MitoCodeMcpError assert issubclass(MitoCodeMcpConfigError, MitoCodeMcpError) diff --git a/test/test_mcp_manager.py b/test/test_mcp_manager.py index f2c2b03..70f0984 100644 --- a/test/test_mcp_manager.py +++ b/test/test_mcp_manager.py @@ -11,21 +11,21 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) -from mitocode.backend.exception.mitocode_exception import MitoCodeMcpConfigError -from mitocode.backend.mcp.mcp_client import McpClient, McpConnectionState -from mitocode.backend.mcp.mcp_config import McpServerConfig, McpServerKind -from mitocode.backend.mcp.mcp_manager import McpManager, McpServerStatus -from mitocode.backend.tool.tool_manager import ToolManager +from mitocode.core.exception.mitocode_exception import MitoCodeMcpConfigError +from mitocode.core.mcp.mcp_client import McpClient, McpConnectionState +from mitocode.core.mcp.mcp_config import McpServerConfig, McpServerKind +from mitocode.core.mcp.mcp_manager import McpManager, McpServerStatus +from mitocode.core.tool.tool_manager import ToolManager #: Imports the ``mcp`` package in a process where the tool layer cannot be #: resolved at all, so the one-way ``mcp`` -> (never) ``tool_manager`` #: dependency is checked for real rather than by reading the source. #: -#: Both ``mitocode`` and ``mitocode.backend`` are stubbed as bare packages: +#: Both ``mitocode`` and ``mitocode.core`` are stubbed as bare packages: #: their real ``__init__`` files re-export the agent layer, which imports #: ``tool_manager`` itself, so a real import of either parent would prove #: nothing about the module under test. The stubs carry only ``__path__``, -#: which is what lets ``mitocode.backend.mcp`` load from disk as usual. +#: which is what lets ``mitocode.core.mcp`` load from disk as usual. _IMPORT_WITHOUT_TOOL_LAYER = """ import importlib.abc import os @@ -39,7 +39,7 @@ class _BlockToolLayer(importlib.abc.MetaPathFinder): \"\"\"Make the whole tool layer unimportable, however it is reached.\"\"\" def find_spec(self, fullname, path=None, target=None): - if fullname.startswith("mitocode.backend.tool"): + if fullname.startswith("mitocode.core.tool"): raise ImportError(f"{fullname} is not importable here") return None @@ -57,15 +57,15 @@ def _stub_package(name, path): _stub_package("mitocode", SRC_DIR) -_stub_package("mitocode.backend", os.path.join(SRC_DIR, "mitocode", "backend")) +_stub_package("mitocode.core", os.path.join(SRC_DIR, "mitocode", "core")) sys.meta_path.insert(0, _BlockToolLayer()) -import mitocode.backend.mcp as mcp +import mitocode.core.mcp as mcp def leaked(): \"\"\"List the tool-layer modules this import dragged in.\"\"\" - return sorted(m for m in sys.modules if m.startswith("mitocode.backend.tool")) + return sorted(m for m in sys.modules if m.startswith("mitocode.core.tool")) assert not leaked(), f"importing the mcp package pulled in the tool layer: {leaked()}" @@ -1561,7 +1561,7 @@ async def test_status_before_start_reports_a_disconnected_server(): def test_mcp_package_exports_the_manager_and_its_neighbours(): """Every name in ``__all__`` resolves; a stale entry is a failed import.""" - from mitocode.backend import mcp + from mitocode.core import mcp assert mcp.McpManager is McpManager assert mcp.McpServerStatus is McpServerStatus @@ -1584,7 +1584,7 @@ def test_mcp_package_imports_without_the_tool_layer(): The plan fixes the dependency direction: ``mcp`` never imports ``tool_manager``. A reference kept under ``TYPE_CHECKING`` is invisible to - this probe, which is why the block covers the whole ``mitocode.backend.tool`` + this probe, which is why the block covers the whole ``mitocode.core.tool`` package rather than one name. """ result = _run_import_probe(_IMPORT_WITHOUT_TOOL_LAYER) diff --git a/test/test_orchestrator_and_bridge.py b/test/test_orchestrator_and_bridge.py index 00b4e6d..347e838 100644 --- a/test/test_orchestrator_and_bridge.py +++ b/test/test_orchestrator_and_bridge.py @@ -7,13 +7,13 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) -from mitocode.backend.agent.agent_runtime import AgentRuntime -from mitocode.backend.agent.agent_session import AgentSession -from mitocode.backend.agent.agent_orchestrator import AgentOrchestrator -from mitocode.backend.agent.agent_state import AgentState -from mitocode.backend.bridge.event_adapter import EventBridge -from mitocode.backend.chat_provider.sample_chat_provider import _SampleChatProvider -from mitocode.backend.tool.tool_manager import ToolManager +from mitocode.core.agent.agent_runtime import AgentRuntime +from mitocode.core.agent.agent_session import AgentSession +from mitocode.core.agent.agent_orchestrator import AgentOrchestrator +from mitocode.core.agent.agent_state import AgentState +from mitocode.core.bridge.event_adapter import EventBridge +from mitocode.core.chat_provider.sample_chat_provider import _SampleChatProvider +from mitocode.core.tool.tool_manager import ToolManager class FakeChunk: diff --git a/test/test_tool_manager.py b/test/test_tool_manager.py index 70cac36..5c3c3ca 100644 --- a/test/test_tool_manager.py +++ b/test/test_tool_manager.py @@ -12,11 +12,11 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) -from mitocode.backend.agent.agent_session import AgentSession -from mitocode.backend.agent.session_factory import SessionFactory -from mitocode.backend.chat_provider.sample_chat_provider import _SampleChatProvider -from mitocode.backend.exception.mitocode_exception import MitoCodeToolDefinitionError -from mitocode.backend.tool.tool_manager import ( +from mitocode.core.agent.agent_session import AgentSession +from mitocode.core.agent.session_factory import SessionFactory +from mitocode.core.chat_provider.sample_chat_provider import _SampleChatProvider +from mitocode.core.exception.mitocode_exception import MitoCodeToolDefinitionError +from mitocode.core.tool.tool_manager import ( MAX_TOOL_NAME_LENGTH, MCP_TOOL_PREFIX, MCP_TOOL_SEPARATOR, @@ -62,12 +62,12 @@ def leaked(): return sorted( m for m in sys.modules - if m.split(".")[0] in ("fastmcp", "mcp") or m.startswith("mitocode.backend.mcp") + if m.split(".")[0] in ("fastmcp", "mcp") or m.startswith("mitocode.core.mcp") ) sys.meta_path.insert(0, _BlockMcpSdk()) -import mitocode.backend.tool.tool_manager as tool_manager +import mitocode.core.tool.tool_manager as tool_manager assert not leaked(), f"mcp package imported at import time: {leaked()}" @@ -1020,7 +1020,7 @@ def test_register_mcp_client_registers_nothing_from_an_empty_catalogue(): manager = ToolManager() client = _fake_mcp_client("files", []) - with mock.patch("mitocode.backend.tool.tool_manager.logger") as fake_logger: + with mock.patch("mitocode.core.tool.tool_manager.logger") as fake_logger: specs = manager.register_mcp_client(client) assert specs == [], "an empty catalogue yields no specs" @@ -1078,7 +1078,7 @@ def mcp__files__read(): return "builtin" client = _fake_mcp_client("files", [_fake_tool("read", description="remote")]) - with mock.patch("mitocode.backend.tool.tool_manager.logger") as fake_logger: + with mock.patch("mitocode.core.tool.tool_manager.logger") as fake_logger: specs = manager.register_mcp_client(client) assert specs == [], "a colliding tool is not registered" @@ -1093,7 +1093,7 @@ def test_register_mcp_client_does_not_warn_when_every_name_is_free(): manager = ToolManager() client = _fake_mcp_client("files", [_fake_tool("read", description="remote")]) - with mock.patch("mitocode.backend.tool.tool_manager.logger") as fake_logger: + with mock.patch("mitocode.core.tool.tool_manager.logger") as fake_logger: specs = manager.register_mcp_client(client) assert len(specs) == 1, "the tool was registered" diff --git a/test/test_workspace.py b/test/test_workspace.py index a335dbf..5610583 100644 --- a/test/test_workspace.py +++ b/test/test_workspace.py @@ -1,5 +1,5 @@ """ -Unit tests for Workspace class in mitocode.backend.workspace.workspace_manager. +Unit tests for Workspace class in mitocode.core.workspace.workspace_manager. Covers: _convert_to_path, __init__, new_workspace, init_from_path, dump, _validate_within_workspace. """ @@ -10,12 +10,12 @@ import pytest -from mitocode.backend.exception.mitocode_exception import ( +from mitocode.core.exception.mitocode_exception import ( MitoCodePathConvertError, MitoCodeWorkspaceInitError, MitoCodeWorkspaceDumpError, ) -from mitocode.backend.workspace.workspace import ( +from mitocode.core.workspace.workspace import ( MITOCODE_CONFIG_PATH, Workspace, ) diff --git a/test/test_workspace_async.py b/test/test_workspace_async.py index 775f7c5..83ad7fa 100644 --- a/test/test_workspace_async.py +++ b/test/test_workspace_async.py @@ -5,8 +5,8 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src")) -from mitocode.backend.workspace.workspace import Workspace -from mitocode.backend.workspace.migration import BasicMigration +from mitocode.core.workspace.workspace import Workspace +from mitocode.core.workspace.migration import BasicMigration @pytest.mark.asyncio