222 lines
7.3 KiB
Python
222 lines
7.3 KiB
Python
"""Workflow workstream integration — posts workflow events to the central
|
|
Communication system (G-WORK).
|
|
|
|
Replaces the old notification-based workflow messages with typed
|
|
CommMessage blocks: status, handoff, approval, action, and error.
|
|
|
|
Used by the WorkflowEngine to post step transitions, approvals,
|
|
errors, and completions to the workstream.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import uuid
|
|
from typing import Any
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def post_workflow_status(
|
|
db: AsyncSession,
|
|
tenant_id: uuid.UUID,
|
|
instance_id: uuid.UUID,
|
|
workflow_name: str,
|
|
status: str,
|
|
step_index: int | None = None,
|
|
step_name: str | None = None,
|
|
user_id: uuid.UUID | None = None,
|
|
) -> dict[str, Any] | None:
|
|
"""Post a workflow status update to the workstream.
|
|
|
|
Creates a CommMessage with a typed ``workflow_status`` block.
|
|
"""
|
|
try:
|
|
from app.plugins.builtins.kommunikation.contracts import KommunikationContract
|
|
contract = KommunikationContract
|
|
post_fn = contract.get_function("post_message")
|
|
if post_fn is None:
|
|
# Fallback to system notification
|
|
from app.core.notifications import post_system_message
|
|
if user_id:
|
|
await post_system_message(
|
|
db, tenant_id, user_id, "workflow_status",
|
|
f"Workflow: {workflow_name}",
|
|
f"Status: {status}" + (f" (Step: {step_name})" if step_name else ""),
|
|
)
|
|
return None
|
|
|
|
block = {
|
|
"type": "workflow_status",
|
|
"workflow_name": workflow_name,
|
|
"instance_id": str(instance_id),
|
|
"status": status,
|
|
"step_index": step_index,
|
|
"step_name": step_name,
|
|
}
|
|
return await post_fn(
|
|
db=db,
|
|
tenant_id=tenant_id,
|
|
sender_id=None, # System sender
|
|
sender_type="system",
|
|
message_type="workflow_status",
|
|
content=f"Workflow '{workflow_name}' → {status}",
|
|
blocks=[block],
|
|
)
|
|
except Exception as e:
|
|
logger.warning("Failed to post workflow status to workstream: %s", e)
|
|
return None
|
|
|
|
|
|
async def post_workflow_handoff(
|
|
db: AsyncSession,
|
|
tenant_id: uuid.UUID,
|
|
instance_id: uuid.UUID,
|
|
workflow_name: str,
|
|
handoff_type: str, # review_needed, action_required, waiting_for_user
|
|
assignee_id: uuid.UUID | None = None,
|
|
assignee_type: str = "user",
|
|
description: str = "",
|
|
user_id: uuid.UUID | None = None,
|
|
) -> dict[str, Any] | None:
|
|
"""Post a workflow handoff to the workstream.
|
|
|
|
Creates a CommMessage with a typed ``workflow_handoff`` block.
|
|
The handoff indicates that the workflow is waiting for human input.
|
|
"""
|
|
try:
|
|
from app.plugins.builtins.kommunikation.contracts import KommunikationContract
|
|
contract = KommunikationContract
|
|
post_fn = contract.get_function("post_message")
|
|
if post_fn is None:
|
|
from app.core.notifications import post_system_message
|
|
if assignee_id:
|
|
await post_system_message(
|
|
db, tenant_id, assignee_id, "workflow_handoff",
|
|
f"Workflow Handoff: {workflow_name}",
|
|
f"{handoff_type}: {description}",
|
|
)
|
|
return None
|
|
|
|
block = {
|
|
"type": "workflow_handoff",
|
|
"workflow_name": workflow_name,
|
|
"instance_id": str(instance_id),
|
|
"handoff_type": handoff_type,
|
|
"assignee_id": str(assignee_id) if assignee_id else None,
|
|
"assignee_type": assignee_type,
|
|
"description": description,
|
|
}
|
|
return await post_fn(
|
|
db=db,
|
|
tenant_id=tenant_id,
|
|
sender_id=None,
|
|
sender_type="system",
|
|
message_type="workflow_handoff",
|
|
content=f"Workflow '{workflow_name}' → {handoff_type}",
|
|
blocks=[block],
|
|
)
|
|
except Exception as e:
|
|
logger.warning("Failed to post workflow handoff to workstream: %s", e)
|
|
return None
|
|
|
|
|
|
async def post_workflow_error(
|
|
db: AsyncSession,
|
|
tenant_id: uuid.UUID,
|
|
instance_id: uuid.UUID,
|
|
workflow_name: str,
|
|
error: str,
|
|
step_index: int | None = None,
|
|
step_name: str | None = None,
|
|
user_id: uuid.UUID | None = None,
|
|
) -> dict[str, Any] | None:
|
|
"""Post a workflow error to the workstream."""
|
|
try:
|
|
from app.plugins.builtins.kommunikation.contracts import KommunikationContract
|
|
contract = KommunikationContract
|
|
post_fn = contract.get_function("post_message")
|
|
if post_fn is None:
|
|
from app.core.notifications import post_system_message
|
|
if user_id:
|
|
await post_system_message(
|
|
db, tenant_id, user_id, "workflow_error",
|
|
f"Workflow Error: {workflow_name}",
|
|
f"Error at step {step_name or step_index}: {error}",
|
|
)
|
|
return None
|
|
|
|
block = {
|
|
"type": "workflow_error",
|
|
"workflow_name": workflow_name,
|
|
"instance_id": str(instance_id),
|
|
"error": error,
|
|
"step_index": step_index,
|
|
"step_name": step_name,
|
|
}
|
|
return await post_fn(
|
|
db=db,
|
|
tenant_id=tenant_id,
|
|
sender_id=None,
|
|
sender_type="system",
|
|
message_type="workflow_error",
|
|
content=f"Workflow '{workflow_name}' → Error: {error}",
|
|
blocks=[block],
|
|
)
|
|
except Exception as e:
|
|
logger.warning("Failed to post workflow error to workstream: %s", e)
|
|
return None
|
|
|
|
|
|
async def post_workflow_completed(
|
|
db: AsyncSession,
|
|
tenant_id: uuid.UUID,
|
|
instance_id: uuid.UUID,
|
|
workflow_name: str,
|
|
result: dict[str, Any] | None = None,
|
|
user_id: uuid.UUID | None = None,
|
|
) -> dict[str, Any] | None:
|
|
"""Post a workflow completion to the workstream."""
|
|
try:
|
|
from app.plugins.builtins.kommunikation.contracts import KommunikationContract
|
|
contract = KommunikationContract
|
|
post_fn = contract.get_function("post_message")
|
|
if post_fn is None:
|
|
from app.core.notifications import post_system_message
|
|
if user_id:
|
|
await post_system_message(
|
|
db, tenant_id, user_id, "workflow_completed",
|
|
f"Workflow Completed: {workflow_name}",
|
|
f"Workflow '{workflow_name}' has been completed successfully.",
|
|
)
|
|
return None
|
|
|
|
block = {
|
|
"type": "workflow_completed",
|
|
"workflow_name": workflow_name,
|
|
"instance_id": str(instance_id),
|
|
"result": result or {},
|
|
}
|
|
return await post_fn(
|
|
db=db,
|
|
tenant_id=tenant_id,
|
|
sender_id=None,
|
|
sender_type="system",
|
|
message_type="workflow_completed",
|
|
content=f"Workflow '{workflow_name}' → Completed",
|
|
blocks=[block],
|
|
)
|
|
except Exception as e:
|
|
logger.warning("Failed to post workflow completion to workstream: %s", e)
|
|
return None
|
|
|
|
|
|
__all__ = [
|
|
"post_workflow_status",
|
|
"post_workflow_handoff",
|
|
"post_workflow_error",
|
|
"post_workflow_completed",
|
|
]
|