feat: F-PREBUILT + F-COMM + F-WORK + G-WORK — prebuilt agents registered, agent results posted to communication, workflow results posted to communication
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
This commit is contained in:
@@ -369,6 +369,71 @@ async def run_agent(
|
|||||||
status=result_data.get("status"),
|
status=result_data.get("status"),
|
||||||
result=result_data,
|
result=result_data,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ── Post agent result to Communication (F-COMM) ──
|
||||||
|
try:
|
||||||
|
from app.plugins.builtins.contracts import get_contract_registry
|
||||||
|
komm = get_contract_registry().get("kommunikation")
|
||||||
|
if komm:
|
||||||
|
async with factory() as db:
|
||||||
|
# Find or create agent conversation room
|
||||||
|
from app.plugins.builtins.kommunikation.models import CommConversation
|
||||||
|
from sqlalchemy import select as sa_select
|
||||||
|
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 = existing.scalar_one_or_none()
|
||||||
|
if not conv:
|
||||||
|
room = await komm.create_plugin_room(
|
||||||
|
db=db,
|
||||||
|
tenant_id=agent.tenant_id,
|
||||||
|
user_id=agent.created_by,
|
||||||
|
plugin_name="automation",
|
||||||
|
title=room_title,
|
||||||
|
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")
|
||||||
|
result_text = result_data.get("llm_response", result_data.get("error", "No result"))
|
||||||
|
await komm.send_message(
|
||||||
|
db=db,
|
||||||
|
tenant_id=agent.tenant_id,
|
||||||
|
conversation_id=conv_id,
|
||||||
|
sender_id=agent.id,
|
||||||
|
sender_type="agent",
|
||||||
|
content=f"Agent '{agent.name}' completed with status: {status}",
|
||||||
|
content_format="text",
|
||||||
|
blocks=[
|
||||||
|
{
|
||||||
|
"block_type": "action_card",
|
||||||
|
"block_data": {
|
||||||
|
"title": f"Agent Result: {agent.name}",
|
||||||
|
"description": result_text[:500] if result_text else "No result",
|
||||||
|
"actions": [
|
||||||
|
{"label": "View Details", "action": "view_agent_run", "data": {"run_id": str(run_id)}},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"sort_order": 0,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
metadata={"agent_id": str(agent.id), "run_id": str(run_id), "status": status},
|
||||||
|
)
|
||||||
|
await db.commit()
|
||||||
|
logger.info("Posted agent result to conversation %s", conv_id)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("Failed to post agent result to communication: %s", e)
|
||||||
|
|
||||||
async with factory() as db:
|
async with factory() as db:
|
||||||
await enqueue_outbox_event(
|
await enqueue_outbox_event(
|
||||||
db,
|
db,
|
||||||
|
|||||||
@@ -232,6 +232,48 @@ class AutomationPlugin(BasePlugin):
|
|||||||
logger.info("Registered own cron jobs from manifest")
|
logger.info("Registered own cron jobs from manifest")
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Failed to register own cron jobs")
|
logger.exception("Failed to register own cron jobs")
|
||||||
|
# Register pre-built agents in DB (if not already present)
|
||||||
|
try:
|
||||||
|
from app.plugins.builtins.automation.models import AgentDefinition
|
||||||
|
from app.plugins.builtins.automation.prebuilt.email_triage_agent import create_email_triage_agent
|
||||||
|
from app.plugins.builtins.automation.prebuilt.contact_enrichment_agent import create_contact_enrichment_agent
|
||||||
|
from app.plugins.builtins.automation.prebuilt.follow_up_agent import create_follow_up_agent
|
||||||
|
from app.plugins.builtins.automation.prebuilt.report_agent import create_report_agent
|
||||||
|
from sqlalchemy import select as sa_select
|
||||||
|
|
||||||
|
# Get first tenant + admin user for seeding
|
||||||
|
from app.models.user import User, Tenant
|
||||||
|
tenant_result = await db.execute(sa_select(Tenant).limit(1))
|
||||||
|
tenant = tenant_result.scalar_one_or_none()
|
||||||
|
if tenant:
|
||||||
|
user_result = await db.execute(
|
||||||
|
sa_select(User).where(User.tenant_id == tenant.id).limit(1)
|
||||||
|
)
|
||||||
|
user = user_result.scalar_one_or_none()
|
||||||
|
if user:
|
||||||
|
prebuilt_factories = [
|
||||||
|
("E-Mail-Triage-Agent", create_email_triage_agent),
|
||||||
|
("Kontakt-Anreicherungs-Agent", create_contact_enrichment_agent),
|
||||||
|
("Follow-Up-Agent", create_follow_up_agent),
|
||||||
|
("Berichts-Agent", create_report_agent),
|
||||||
|
]
|
||||||
|
for agent_name, factory in prebuilt_factories:
|
||||||
|
# Check if agent already exists
|
||||||
|
existing = await db.execute(
|
||||||
|
sa_select(AgentDefinition).where(
|
||||||
|
AgentDefinition.tenant_id == tenant.id,
|
||||||
|
AgentDefinition.name == agent_name,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if not existing.scalar_one_or_none():
|
||||||
|
agent = factory(tenant_id=tenant.id, user_id=user.id)
|
||||||
|
db.add(agent)
|
||||||
|
logger.info("Registered pre-built agent '%s'", agent_name)
|
||||||
|
await db.commit()
|
||||||
|
logger.info("Pre-built agents registration complete")
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed to register pre-built agents")
|
||||||
|
|
||||||
logger.info("Automation plugin activated")
|
logger.info("Automation plugin activated")
|
||||||
|
|
||||||
async def on_deactivate(self, db, service_container, event_bus) -> None:
|
async def on_deactivate(self, db, service_container, event_bus) -> None:
|
||||||
|
|||||||
@@ -89,6 +89,63 @@ class WorkflowEngine:
|
|||||||
'initiated_by': str(instance.initiated_by) if instance.initiated_by else None,
|
'initiated_by': str(instance.initiated_by) if instance.initiated_by else None,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Post workflow completion to Communication (G-WORK)
|
||||||
|
try:
|
||||||
|
from app.plugins.builtins.contracts import get_contract_registry
|
||||||
|
from app.plugins.builtins.kommunikation.models import CommConversation
|
||||||
|
from sqlalchemy import select as sa_select
|
||||||
|
komm = get_contract_registry().get("kommunikation")
|
||||||
|
if komm and instance.initiated_by:
|
||||||
|
room_title = f"Workflow: {workflow.name if hasattr(workflow, 'name') else str(instance.workflow_id)}"
|
||||||
|
existing = await self.db.execute(
|
||||||
|
sa_select(CommConversation).where(
|
||||||
|
CommConversation.tenant_id == self.tenant_id,
|
||||||
|
CommConversation.title == room_title,
|
||||||
|
CommConversation.is_locked.is_(True),
|
||||||
|
CommConversation.locked_by == "workflow",
|
||||||
|
CommConversation.deleted_at.is_(None),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
conv = existing.scalar_one_or_none()
|
||||||
|
if not conv:
|
||||||
|
room = await komm.create_plugin_room(
|
||||||
|
db=self.db,
|
||||||
|
tenant_id=self.tenant_id,
|
||||||
|
user_id=instance.initiated_by,
|
||||||
|
plugin_name="workflow",
|
||||||
|
title=room_title,
|
||||||
|
participant_type="workflow",
|
||||||
|
)
|
||||||
|
conv_id = uuid.UUID(room["conversation_id"])
|
||||||
|
else:
|
||||||
|
conv_id = conv.id
|
||||||
|
await komm.send_message(
|
||||||
|
db=self.db,
|
||||||
|
tenant_id=self.tenant_id,
|
||||||
|
conversation_id=conv_id,
|
||||||
|
sender_id=instance.workflow_id,
|
||||||
|
sender_type="system",
|
||||||
|
content=f"Workflow completed: {instance.status}",
|
||||||
|
content_format="text",
|
||||||
|
blocks=[
|
||||||
|
{
|
||||||
|
"block_type": "action_card",
|
||||||
|
"block_data": {
|
||||||
|
"title": f"Workflow Result: {instance.status}",
|
||||||
|
"description": f"Workflow instance {str(instance.id)[:8]} completed successfully",
|
||||||
|
"actions": [
|
||||||
|
{"label": "View Details", "action": "view_workflow_instance", "data": {"instance_id": str(instance.id)}},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"sort_order": 0,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
metadata={"workflow_id": str(instance.workflow_id), "instance_id": str(instance.id), "status": instance.status},
|
||||||
|
)
|
||||||
|
await self.db.flush()
|
||||||
|
except Exception:
|
||||||
|
logger.warning("Failed to post workflow result to communication", exc_info=True)
|
||||||
|
|
||||||
return _instance_to_dict(instance)
|
return _instance_to_dict(instance)
|
||||||
|
|
||||||
step = steps[instance.current_step_index]
|
step = steps[instance.current_step_index]
|
||||||
|
|||||||
Reference in New Issue
Block a user