feat: Unified Messaging System — kommunikation plugin, AI/Proactive/System participants, MessageSidebar, Rich Content Renderer

Phase 1: Backend plugin kommunikation (13 files, 10 tables, REST API, WebSocket, RBAC, DMS Bridge, Participant Registry, Mini-App Registry, Search Provider)
Phase 2: AI plugins as participants (ai_assistant + ai_proactive dock as participants, heartbeat job)
Phase 3: system_notif plugin (system events → chat messages, pinned System room)
Phase 4: Frontend MessageSidebar (replaces AISidebar, same design, comm API client, WebSocket hook, commStore)
Phase 5: Rich Content Block Renderer (11 components: Markdown, HTML, Image, Audio, Video, File, ActionCard, ContactCard, MiniApp, BlockRenderer)
BasePlugin: added services property + _container in on_activate
This commit is contained in:
Agent Zero
2026-07-22 01:22:15 +02:00
parent 5980d38c66
commit cc3ac9a43d
45 changed files with 8154 additions and 113 deletions
+81
View File
@@ -314,3 +314,84 @@ async def deep_analysis(
entity_type,
entity_id,
)
# ─── Heartbeat Job ───
async def heartbeat(ctx: dict[str, Any], user_id: str, tenant_id: str) -> None:
"""Heartbeat job for the AI Proactive plugin.
Runs every 5 minutes (scheduled by the plugin on activation).
Posts a status message to the 'Live KI' room in the kommunikation system.
"""
try:
uid = uuid.UUID(user_id)
tid = uuid.UUID(tenant_id)
except (ValueError, TypeError):
logger.warning("heartbeat: invalid UUID parameters (user_id=%s, tenant_id=%s)", user_id, tenant_id)
return
try:
from app.core.db import create_db_session
from app.plugins.builtins.kommunikation.services import (
create_plugin_room,
send_message,
)
async with create_db_session(tid) as db:
# Create or get the 'Live KI' room for this user
room = await create_plugin_room(
db,
tid,
uid,
plugin_name="ai_proactive",
title="Live KI",
participant_type="ai_proactive",
user_role="member",
)
conversation_id_str = room.get("id")
if not conversation_id_str:
logger.warning("heartbeat: could not create/get Live KI room")
return
conversation_id = uuid.UUID(conversation_id_str)
# Gather some stats for the status message
from sqlalchemy import func, select
from app.models.contact import Contact
contact_count_result = await db.execute(
select(func.count()).select_from(Contact).where(
Contact.tenant_id == tid,
Contact.deleted_at.is_(None),
)
)
contact_count = contact_count_result.scalar() or 0
# Build status message
from datetime import datetime, timezone
now_str = datetime.now(timezone.utc).strftime("%H:%M:%S")
status_content = (
f"**System aktiv** — überwacht {contact_count} Kontakte\n"
f"_Letztes Update: {now_str}_"
)
await send_message(
db=db,
tenant_id=tid,
conversation_id=conversation_id,
sender_id=None,
sender_type="ai_proactive",
content=status_content,
content_format="markdown",
)
await db.commit()
logger.info("heartbeat: posted status to Live KI room for user %s", user_id)
except Exception:
logger.exception("heartbeat: error posting status message")