1167644824
Check Cross-Plugin Imports / check (push) Has been cancelled
All built-in plugins should be auto-activated. The is_core flag was only set on some plugins, leaving Mail, DMS, Calendar, Automation, Unified Search etc. inactive by default.
151 lines
5.7 KiB
Python
151 lines
5.7 KiB
Python
"""Proactive AI Agent plugin — context-aware suggestions built on
|
|
unified_search and ai_assistant.
|
|
|
|
Listens to context-change events, gathers entity data, generates LLM-powered
|
|
suggestions, pushes them via SSE, and registers AI tools for the assistant.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from app.plugins.base import BasePlugin
|
|
from app.plugins.manifest import PluginManifest, PluginRouteDef, FrontendSettingsPage
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class AIProactivePlugin(BasePlugin):
|
|
"""Proactive KI Agent that monitors user context and suggests actions."""
|
|
|
|
manifest = PluginManifest(
|
|
name="ai_proactive",
|
|
version="1.0.0",
|
|
display_name="Proaktiver KI Agent",
|
|
description=(
|
|
"Überwacht den User-Kontext, generiert proaktiv Vorschläge per LLM "
|
|
"und pusht diese via SSE. Nutzt unified_search und ai_assistant."
|
|
),
|
|
dependencies=["ai_assistant", "unified_search", "kommunikation"],
|
|
routes=[
|
|
PluginRouteDef(
|
|
path="/api/v1/ai-proactive",
|
|
module="app.plugins.builtins.ai_proactive.routes",
|
|
router_attr="router",
|
|
),
|
|
],
|
|
events=["context.view_changed", "context.entity_selected"],
|
|
migrations=["0001_initial.sql"],
|
|
permissions=[
|
|
"ai_proactive:read",
|
|
"ai_proactive:write",
|
|
"ai_proactive:config",
|
|
],
|
|
is_core=True,
|
|
settings_pages=[
|
|
FrontendSettingsPage(path='ai-proactive', label_key='settings.aiProactive', label='Proactive AI', component='@/pages/ProactiveAISettings', icon='Sparkles', order=61),
|
|
],
|
|
author="LeoCRM Team",
|
|
min_app_version="1.0.0",
|
|
hooks=["contact.after_create", "mail.after_send"],
|
|
contract_version="1.0.0",
|
|
)
|
|
|
|
def __init__(self) -> None:
|
|
super().__init__()
|
|
self._proactive_handler = None
|
|
|
|
async def on_activate(self, db, service_container, event_bus) -> None:
|
|
"""Register context tools, subscribe to events, and register as participant."""
|
|
await super().on_activate(db, service_container, event_bus)
|
|
try:
|
|
from app.plugins.builtins.ai_proactive.context_tools import (
|
|
register_context_tools,
|
|
)
|
|
from app.plugins.builtins.ai_assistant.contracts import (
|
|
get_tool_registry,
|
|
)
|
|
|
|
register_context_tools(get_tool_registry())
|
|
logger.info("AI Proactive context tools registered")
|
|
except Exception:
|
|
logger.exception("Failed to register AI Proactive context tools")
|
|
|
|
# Register as participant in the kommunikation system
|
|
try:
|
|
from app.plugins.builtins.ai_proactive.participant_handler import (
|
|
AIProactiveParticipantHandler,
|
|
)
|
|
from app.plugins.builtins.kommunikation.contracts import (
|
|
get_participant_registry,
|
|
)
|
|
|
|
self._proactive_handler = AIProactiveParticipantHandler(service_container)
|
|
get_participant_registry().register("ai_proactive", self._proactive_handler)
|
|
logger.info("AI Proactive registered as participant 'ai_proactive'")
|
|
except Exception:
|
|
logger.exception("Failed to register AI Proactive as participant")
|
|
|
|
async def on_deactivate(self, db, service_container, event_bus) -> None:
|
|
"""Unregister tools, event listeners, and participant."""
|
|
# Contract abmelden
|
|
from app.plugins.builtins.contracts import get_contract_registry
|
|
get_contract_registry().unregister(self.manifest.name)
|
|
|
|
# Unregister from participant registry
|
|
try:
|
|
from app.plugins.builtins.kommunikation.contracts import (
|
|
get_participant_registry,
|
|
)
|
|
|
|
get_participant_registry().unregister("ai_proactive")
|
|
logger.info("AI Proactive unregistered as participant 'ai_proactive'")
|
|
except Exception:
|
|
logger.exception("Failed to unregister AI Proactive as participant")
|
|
|
|
self._proactive_handler = None
|
|
|
|
try:
|
|
from app.plugins.builtins.ai_assistant.contracts import (
|
|
get_tool_registry,
|
|
)
|
|
|
|
get_tool_registry().unregister_plugin("ai_proactive")
|
|
logger.info("AI Proactive context tools unregistered")
|
|
except Exception:
|
|
logger.exception("Failed to unregister AI Proactive context tools")
|
|
await super().on_deactivate(db, service_container, event_bus)
|
|
|
|
# ─── Event Handlers ───
|
|
|
|
async def on_context_view_changed(self, payload: dict[str, Any]) -> None:
|
|
"""Handle context.view_changed event."""
|
|
from app.plugins.builtins.ai_proactive.services import handle_context_change
|
|
|
|
await handle_context_change(payload)
|
|
|
|
async def on_context_entity_selected(self, payload: dict[str, Any]) -> None:
|
|
"""Handle context.entity_selected event."""
|
|
from app.plugins.builtins.ai_proactive.services import handle_context_change
|
|
|
|
await handle_context_change(payload)
|
|
|
|
def get_notification_types(self) -> list[dict[str, Any]]:
|
|
return [
|
|
{
|
|
"type_key": "ai_suggestion",
|
|
"category": "ai",
|
|
"label": "KI Vorschlag",
|
|
"description": "Proaktiver KI-Vorschlag",
|
|
"is_enabled_by_default": True,
|
|
},
|
|
{
|
|
"type_key": "ai_suggestion_urgent",
|
|
"category": "ai",
|
|
"label": "Dringender KI Vorschlag",
|
|
"description": "Dringender proaktiver KI-Vorschlag",
|
|
"is_enabled_by_default": True,
|
|
},
|
|
]
|