From 7467c01d3885d571c0bc9a861790e67661498c3b Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Sun, 23 Aug 2026 20:29:09 +0200 Subject: [PATCH] refactor(b2): eliminate all cross-plugin imports - contracts for worker/agent_runner/workstream, declared dependency for wiki --- app/core/worker.py | 7 +---- .../builtins/automation/agent_runner.py | 29 +++++++------------ app/plugins/builtins/tasks/workstream.py | 8 ++--- .../builtins/unified_search/contracts.py | 9 ++++++ app/plugins/builtins/wiki/plugin.py | 2 +- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/app/core/worker.py b/app/core/worker.py index 5199a48..60749dc 100644 --- a/app/core/worker.py +++ b/app/core/worker.py @@ -170,12 +170,7 @@ async def on_startup(ctx: dict[str, Any]) -> None: if search_contract is not None: factory = async_session async with factory() as db: - # auto_register_providers is not exposed via contract yet; - # use the contract's get_search_registry to access providers - from app.plugins.builtins.unified_search.provider_registry import ( - auto_register_providers, - ) - await auto_register_providers(db) + await search_contract.auto_register_providers(db) logger.info("Search providers registered for worker") else: logger.debug("Unified search plugin not available — skipping provider registration") diff --git a/app/plugins/builtins/automation/agent_runner.py b/app/plugins/builtins/automation/agent_runner.py index 9c416e4..a603ae9 100644 --- a/app/plugins/builtins/automation/agent_runner.py +++ b/app/plugins/builtins/automation/agent_runner.py @@ -110,9 +110,9 @@ async def run_agent( try: from app.plugins.builtins.contracts import get_contract mail_contract = get_contract("mail") - if mail_contract and hasattr(mail_contract, "get_recent_mails"): + if mail_contract and hasattr(mail_contract, "Mail"): from sqlalchemy import select as _select - from app.plugins.builtins.mail.models import Mail + Mail = mail_contract.Mail async with factory() as db: mail_q = await db.execute( _select(Mail) @@ -379,23 +379,16 @@ async def run_agent( komm = get_contract_registry().get("kommunikation") if komm: async with factory() as db: - # Find or create agent conversation room - from app.plugins.builtins.contracts import get_contract as _get_contract - _komm_contract = _get_contract("kommunikation") - from app.plugins.builtins.kommunikation.models import CommConversation - from sqlalchemy import select as sa_select + # Find or create agent conversation room via contract + # (find_locked_room_id matches create_plugin_room semantics) room_title = f"Agent: {agent.name}" - existing = await db.execute( - sa_select(CommConversation).where( - CommConversation.tenant_id == agent.tenant_id, - CommConversation.title == room_title, - CommConversation.is_locked.is_(True), - CommConversation.locked_by == "automation", - CommConversation.deleted_at.is_(None), - ) + conv_id = await komm.find_locked_room_id( + db=db, + tenant_id=agent.tenant_id, + plugin_name="automation", + title=room_title, ) - conv = existing.scalar_one_or_none() - if not conv: + if not conv_id: room = await komm.create_plugin_room( db=db, tenant_id=agent.tenant_id, @@ -405,8 +398,6 @@ async def run_agent( participant_type="agent", ) conv_id = uuid.UUID(room["conversation_id"]) - else: - conv_id = conv.id # Post result as message with action_card block status = result_data.get("status", "unknown") diff --git a/app/plugins/builtins/tasks/workstream.py b/app/plugins/builtins/tasks/workstream.py index 7ab2d58..8f85da1 100644 --- a/app/plugins/builtins/tasks/workstream.py +++ b/app/plugins/builtins/tasks/workstream.py @@ -67,10 +67,10 @@ async def post_task_to_workstream( try: from app.plugins.builtins.contracts import get_contract _komm = get_contract("kommunikation") - if _komm and hasattr(_komm, "send_message"): - send_message = _komm.send_message - else: - from app.plugins.builtins.kommunikation.services import send_message + if not _komm or not hasattr(_komm, "send_message"): + logger.warning("kommunikation contract unavailable - skipping workstream post for task %s", task.id) + return None + send_message = _komm.send_message block_type = "goal_card" if task.task_type in ("goal", "milestone") else "task_card" block_data = _goal_card_data(task) if block_type == "goal_card" else _task_card_data(task) diff --git a/app/plugins/builtins/unified_search/contracts.py b/app/plugins/builtins/unified_search/contracts.py index b9fc553..ab00070 100644 --- a/app/plugins/builtins/unified_search/contracts.py +++ b/app/plugins/builtins/unified_search/contracts.py @@ -50,6 +50,15 @@ class UnifiedSearchContract: simple_search = staticmethod(simple_search) BaseSearchProvider = BaseSearchProvider + @staticmethod + async def auto_register_providers(db: Any) -> None: + """Register providers for all active plugins (worker startup path).""" + from app.plugins.builtins.unified_search.provider_registry import ( + auto_register_providers as _auto_register, + ) + + await _auto_register(db) + @classmethod def get_function(cls, name: str): """Return a callable exposed by this contract, or None if absent.""" diff --git a/app/plugins/builtins/wiki/plugin.py b/app/plugins/builtins/wiki/plugin.py index 1dd4a43..8635100 100644 --- a/app/plugins/builtins/wiki/plugin.py +++ b/app/plugins/builtins/wiki/plugin.py @@ -13,7 +13,7 @@ class WikiPlugin(BasePlugin): version="1.0.0", display_name="Wiki", description="Knowledge articles with Markdown, categories, tags, versioning, entity links.", - dependencies=["permissions"], + dependencies=["permissions", "unified_search"], routes=[ PluginRouteDef(path="/api/v1/wiki", module="app.plugins.builtins.wiki.routes", router_attr="router"), ],