feat(B-HOOK): Lifecycle Hooks + Outbox Events — 55 neue Hooks, 10 Domain Events
Check Cross-Plugin Imports / check (push) Has been cancelled

B-HOOK-CORE: Company Hooks (6: before/after create/update/delete)
B-HOOK-MAIL: Mail Hooks (5: after_receive, before/after_delete, before/after_move)
B-HOOK-DMS: DMS Hooks (10: after_upload, before/after_update/delete/restore, folder CRUD)
B-HOOK-CAL: Calendar Hooks (4: before/after update/delete)
B-HOOK-TASK: Task Hooks (6: before/after create/update/delete)
B-HOOK-COMM: Communication Hooks (8: conversation create, message/edit/delete)
B-HOOK-AI: Agent Hooks (2: before/after_run)
B-HOOK-WF: Workflow Hooks (4: before/after_start, after_complete/cancel)
B-HOOK-TAG: Tag Hooks (8: create/assign/unassign/delete)
B-HOOK-SEARCH: Search Filters (2: before/after_search)

B-EVT-OUTBOX: 10 Domain Events (task.completed, file.created/deleted/restored, mail.received, workflow.started/completed/cancelled, agent.run_started/completed)

B-HOOK-TEST: 79 Tests in test_lifecycle_hooks.py — alle grün
B-HOOK-DOC: Plugin-Dev-Guide Kapitel 8 aktualisiert (Hook-Liste + Outbox Event-Liste)
This commit is contained in:
Agent Zero
2026-08-13 20:54:15 +02:00
parent b231c2d0d3
commit ae228bb484
12 changed files with 1145 additions and 0 deletions
+35
View File
@@ -352,9 +352,21 @@ async def create_instance(
timeout_hours=timeout_hours,
timeout_at=timeout_at,
)
from app.core.hooks import do_action
await do_action("workflow.before_start", instance_id=instance.id, workflow_id=wf_uuid, tenant_id=tenant_id, user_id=user_id)
db.add(instance)
await db.flush()
await db.refresh(instance)
await do_action("workflow.after_start", instance_id=instance.id, workflow_id=wf_uuid, tenant_id=tenant_id, user_id=user_id)
from app.core.outbox import enqueue_outbox_event
await enqueue_outbox_event(
db,
tenant_id,
'workflow.started',
{'instance_id': str(instance.id), 'workflow_id': str(wf_uuid), 'tenant_id': str(tenant_id)},
aggregate_type='workflow_instance',
aggregate_id=instance.id,
)
# Log initial step entry
steps = workflow.steps or []
@@ -567,6 +579,17 @@ async def advance_instance(
action="completed",
actor_id=user_id,
)
from app.core.hooks import do_action
await do_action("workflow.after_complete", instance_id=instance.id, workflow_id=instance.workflow_id, tenant_id=tenant_id, user_id=user_id)
from app.core.outbox import enqueue_outbox_event
await enqueue_outbox_event(
db,
tenant_id,
'workflow.completed',
{'instance_id': str(instance.id), 'workflow_id': str(instance.workflow_id), 'tenant_id': str(tenant_id), 'status': 'completed'},
aggregate_type='workflow_instance',
aggregate_id=instance.id,
)
else:
instance.current_step_index = next_idx
next_step = steps[next_idx]
@@ -626,6 +649,18 @@ async def cancel_instance(
instance.status = "cancelled"
instance.completed_at = datetime.now(UTC)
from app.core.hooks import do_action
await do_action("workflow.after_cancel", instance_id=instance.id, workflow_id=instance.workflow_id, tenant_id=tenant_id, user_id=user_id)
from app.core.outbox import enqueue_outbox_event
await enqueue_outbox_event(
db,
tenant_id,
'workflow.cancelled',
{'instance_id': str(instance.id), 'workflow_id': str(instance.workflow_id), 'tenant_id': str(tenant_id), 'status': 'cancelled'},
aggregate_type='workflow_instance',
aggregate_id=instance.id,
)
# Get current step for history
wf_result = await db.execute(select(Workflow).where(Workflow.id == instance.workflow_id))
workflow = wf_result.scalar_one_or_none()