Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ WORKDIR /app
# Copy virtual environment from builder
COPY --from=builder /app/.venv /app/.venv

# Copy application source and agent configs
# Copy application source
COPY src/ /app/src/
COPY agents/ /app/agents/

# Set Python path and venv
ENV PYTHONPATH=/app:$PYTHONPATH
Expand Down
199 changes: 117 additions & 82 deletions README.md

Large diffs are not rendered by default.

14 changes: 0 additions & 14 deletions src/application/use_cases/load_agent_config.py

This file was deleted.

69 changes: 0 additions & 69 deletions src/application/use_cases/seed_agents.py

This file was deleted.

1 change: 0 additions & 1 deletion src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ class TracingSettings(BaseSettings):


class Settings(BaseSettings):
agents_dir: str = "./agents"
openai_api_key: str | None = None
host: str = "0.0.0.0"
port: int = 8000
Expand Down
60 changes: 14 additions & 46 deletions src/dependencies.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import logging
from pathlib import Path

from miniopy_async import Minio
from miniopy_async.api import Minio
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
from sqlalchemy.pool import AsyncAdaptedQueuePool

from src.application.use_cases.create_agent_config import CreateAgentConfigUseCase
from src.application.use_cases.delete_agent_config import DeleteAgentConfigUseCase
from src.application.use_cases.get_agent_config import GetAgentConfigUseCase
from src.application.use_cases.list_agent_configs import ListAgentConfigsUseCase
from src.application.use_cases.load_agent_config import LoadAgentConfigUseCase
from src.application.use_cases.seed_agents import SeedAgentsUseCase
from src.application.use_cases.send_message import SendMessageUseCase
from src.application.use_cases.stream_message import StreamMessageUseCase
from src.application.use_cases.thread_management import (
Expand All @@ -23,7 +20,6 @@
from src.config import Settings
from src.domain.exceptions import StorageError
from src.domain.ports.thread_repository import ThreadRepository
from src.infrastructure.deepagent.registry import DeepAgentRegistry
from src.infrastructure.mcp.adapter import LangchainMcpToolLoader
from src.infrastructure.minio_store.adapter import MinioAgentConfigStore
from src.infrastructure.persistent_registry.adapter import PersistentAgentRegistry
Expand Down Expand Up @@ -82,15 +78,7 @@ def _create_tracing_provider(settings: Settings):
mcp_tool_loader = LangchainMcpToolLoader()
tracing_provider = _create_tracing_provider(settings)

# Filesystem-based registry (kept for backward compatibility)
agent_registry = DeepAgentRegistry(
agents_dir=Path(settings.agents_dir),
config_loader=agent_config_loader,
mcp_tool_loader=mcp_tool_loader,
tracing_provider=tracing_provider,
)

agents_dir = settings.agents_dir
agent_registry: PersistentAgentRegistry | None = None

# ============= PERSISTENCE (initialized at startup) =============

Expand Down Expand Up @@ -159,23 +147,6 @@ async def close_persistence() -> None:
logger.info("SQLAlchemy engine disposed")


async def seed_builtin_agents() -> None:
"""Seed built-in agents from the configured agents directory."""
if _minio_store is None or _pg_repository is None:
logger.warning("Persistence not initialized, skipping seed")
return

seed_use_case = SeedAgentsUseCase(
config_loader=agent_config_loader,
config_store=_minio_store,
config_repository=_pg_repository,
)
await seed_use_case.execute(agents_dir=Path(settings.agents_dir))
logger.info("Built-in agents seeded from %s", settings.agents_dir)


logger.info("Dependencies initialized (agents_dir=%s)", settings.agents_dir)

# ============= USE CASE PROVIDERS =============


Expand All @@ -186,19 +157,26 @@ def _require_thread_repository() -> ThreadRepository:
return thread_repository


def _require_agent_registry() -> PersistentAgentRegistry:
"""Return agent registry or raise StorageError if not initialized."""
if agent_registry is None:
raise StorageError("Agent registry not initialized. Check persistence connectivity.")
return agent_registry


def get_send_message_use_case() -> SendMessageUseCase:
"""Provide a SendMessageUseCase instance."""
return SendMessageUseCase(agent_registry, _require_thread_repository())
return SendMessageUseCase(_require_agent_registry(), _require_thread_repository())


def get_stream_message_use_case() -> StreamMessageUseCase:
"""Provide a StreamMessageUseCase instance."""
return StreamMessageUseCase(agent_registry, _require_thread_repository())
return StreamMessageUseCase(_require_agent_registry(), _require_thread_repository())


def get_create_thread_use_case() -> CreateThreadUseCase:
"""Provide a CreateThreadUseCase instance."""
return CreateThreadUseCase(_require_thread_repository(), agent_registry)
return CreateThreadUseCase(_require_thread_repository(), _require_agent_registry())


def get_get_thread_use_case() -> GetThreadUseCase:
Expand All @@ -216,16 +194,6 @@ def get_delete_thread_use_case() -> DeleteThreadUseCase:
return DeleteThreadUseCase(_require_thread_repository())


def get_load_agent_config_use_case() -> LoadAgentConfigUseCase:
"""Provide a LoadAgentConfigUseCase instance."""
return LoadAgentConfigUseCase(agent_config_loader)


def get_agents_dir() -> str:
"""Provide the configured agents directory path."""
return agents_dir


def _require_persistence() -> tuple[MinioAgentConfigStore, PostgresAgentConfigRepository]:
"""Return persistence adapters or raise StorageError if not initialized."""
if _minio_store is None or _pg_repository is None:
Expand All @@ -250,7 +218,7 @@ def get_update_agent_config_use_case() -> UpdateAgentConfigUseCase:
config_loader=agent_config_loader,
config_store=store,
config_repository=repo,
agent_registry=agent_registry,
agent_registry=_require_agent_registry(),
)


Expand All @@ -260,7 +228,7 @@ def get_delete_agent_config_use_case() -> DeleteAgentConfigUseCase:
return DeleteAgentConfigUseCase(
config_store=store,
config_repository=repo,
agent_registry=agent_registry,
agent_registry=_require_agent_registry(),
)


Expand Down
68 changes: 0 additions & 68 deletions src/infrastructure/deepagent/registry.py

This file was deleted.

16 changes: 5 additions & 11 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
close_persistence,
init_persistence,
mcp_tool_loader,
seed_builtin_agents,
tracing_provider,
)
from src.domain.exceptions import (
Expand Down Expand Up @@ -57,16 +56,11 @@ def _run_alembic_upgrade() -> None:
async def lifespan(_app: FastAPI):
"""Application lifespan: run migrations, init persistence on startup, cleanup on shutdown."""
logger.info("Application startup initiated")
try:
logger.info("Running database migrations...")
await asyncio.to_thread(_run_alembic_upgrade)
logger.info("Database migrations completed")
await init_persistence()
await seed_builtin_agents()
logger.info("Persistence initialized and agents seeded")
except Exception:
logger.exception("Failed to initialize persistence, falling back to filesystem registry")
logger.info("Application startup complete")
logger.info("Running database migrations...")
await asyncio.to_thread(_run_alembic_upgrade)
logger.info("Database migrations completed")
await init_persistence()
logger.info("Persistence initialized")
yield
logger.info("Application shutdown initiated")
try:
Expand Down
31 changes: 0 additions & 31 deletions tests/unit/test_load_agent_config_use_case.py

This file was deleted.

6 changes: 0 additions & 6 deletions tests/unit/test_mcp_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ def test_mcp_tool_loader_is_langchain_instance(self):
"""The module-level mcp_tool_loader is a LangchainMcpToolLoader."""
assert isinstance(dependencies.mcp_tool_loader, LangchainMcpToolLoader)

def test_agent_registry_received_mcp_tool_loader(self):
"""The agent_registry was constructed with the mcp_tool_loader."""
assert dependencies.agent_registry._mcp_tool_loader is dependencies.mcp_tool_loader


class TestLifespanMcpCleanup:
"""Tests for lifespan MCP cleanup."""
Expand All @@ -33,7 +29,6 @@ async def test_lifespan_calls_mcp_tool_loader_close(self, mock_mcp_tool_loader):
patch("src.main.mcp_tool_loader", mock_mcp_tool_loader),
patch("src.main.close_persistence", AsyncMock()),
patch("src.main.init_persistence", AsyncMock()),
patch("src.main.seed_builtin_agents", AsyncMock()),
patch("src.main.tracing_provider", AsyncMock()),
):
async with lifespan(None):
Expand All @@ -52,7 +47,6 @@ async def test_lifespan_handles_cleanup_gracefully(self):
with (
patch("src.main.close_persistence", mock_close_persistence),
patch("src.main.init_persistence", AsyncMock()),
patch("src.main.seed_builtin_agents", AsyncMock()),
patch("src.main.mcp_tool_loader", mock_mcp),
patch("src.main.tracing_provider", mock_tracing),
):
Expand Down
Loading
Loading