refactor: elegant event dispatch patterns (92% complexity reduction) (#22600)

Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: Claude <noreply@anthropic.com>
pull/22617/head
-LAN- 10 months ago committed by GitHub
parent ffee6f3288
commit 1f9cd99bc2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

File diff suppressed because it is too large Load Diff

@ -1,7 +1,8 @@
import logging import logging
import time import time
from collections.abc import Generator from collections.abc import Callable, Generator
from typing import Optional, Union from contextlib import contextmanager
from typing import Any, Optional, Union
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@ -13,6 +14,7 @@ from core.app.entities.app_invoke_entities import (
WorkflowAppGenerateEntity, WorkflowAppGenerateEntity,
) )
from core.app.entities.queue_entities import ( from core.app.entities.queue_entities import (
MessageQueueMessage,
QueueAgentLogEvent, QueueAgentLogEvent,
QueueErrorEvent, QueueErrorEvent,
QueueIterationCompletedEvent, QueueIterationCompletedEvent,
@ -38,11 +40,13 @@ from core.app.entities.queue_entities import (
QueueWorkflowPartialSuccessEvent, QueueWorkflowPartialSuccessEvent,
QueueWorkflowStartedEvent, QueueWorkflowStartedEvent,
QueueWorkflowSucceededEvent, QueueWorkflowSucceededEvent,
WorkflowQueueMessage,
) )
from core.app.entities.task_entities import ( from core.app.entities.task_entities import (
ErrorStreamResponse, ErrorStreamResponse,
MessageAudioEndStreamResponse, MessageAudioEndStreamResponse,
MessageAudioStreamResponse, MessageAudioStreamResponse,
PingStreamResponse,
StreamResponse, StreamResponse,
TextChunkStreamResponse, TextChunkStreamResponse,
WorkflowAppBlockingResponse, WorkflowAppBlockingResponse,
@ -54,6 +58,7 @@ from core.app.task_pipeline.based_generate_task_pipeline import BasedGenerateTas
from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk from core.base.tts import AppGeneratorTTSPublisher, AudioTrunk
from core.ops.ops_trace_manager import TraceQueueManager from core.ops.ops_trace_manager import TraceQueueManager
from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType from core.workflow.entities.workflow_execution import WorkflowExecution, WorkflowExecutionStatus, WorkflowType
from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState
from core.workflow.repositories.draft_variable_repository import DraftVariableSaverFactory from core.workflow.repositories.draft_variable_repository import DraftVariableSaverFactory
from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository from core.workflow.repositories.workflow_execution_repository import WorkflowExecutionRepository
from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository from core.workflow.repositories.workflow_node_execution_repository import WorkflowNodeExecutionRepository
@ -246,315 +251,492 @@ class WorkflowAppGenerateTaskPipeline:
if tts_publisher: if tts_publisher:
yield MessageAudioEndStreamResponse(audio="", task_id=task_id) yield MessageAudioEndStreamResponse(audio="", task_id=task_id)
def _process_stream_response( @contextmanager
def _database_session(self):
"""Context manager for database sessions."""
with Session(db.engine, expire_on_commit=False) as session:
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
def _ensure_workflow_initialized(self) -> None:
"""Fluent validation for workflow state."""
if not self._workflow_run_id:
raise ValueError("workflow run not initialized.")
def _ensure_graph_runtime_initialized(self, graph_runtime_state: Optional[GraphRuntimeState]) -> GraphRuntimeState:
"""Fluent validation for graph runtime state."""
if not graph_runtime_state:
raise ValueError("graph runtime state not initialized.")
return graph_runtime_state
def _handle_ping_event(self, event: QueuePingEvent, **kwargs) -> Generator[PingStreamResponse, None, None]:
"""Handle ping events."""
yield self._base_task_pipeline._ping_stream_response()
def _handle_error_event(self, event: QueueErrorEvent, **kwargs) -> Generator[ErrorStreamResponse, None, None]:
"""Handle error events."""
err = self._base_task_pipeline._handle_error(event=event)
yield self._base_task_pipeline._error_to_stream_response(err)
def _handle_workflow_started_event(
self, event: QueueWorkflowStartedEvent, **kwargs
) -> Generator[StreamResponse, None, None]:
"""Handle workflow started events."""
# init workflow run
workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start()
self._workflow_run_id = workflow_execution.id_
start_resp = self._workflow_response_converter.workflow_start_to_stream_response(
task_id=self._application_generate_entity.task_id,
workflow_execution=workflow_execution,
)
yield start_resp
def _handle_node_retry_event(self, event: QueueNodeRetryEvent, **kwargs) -> Generator[StreamResponse, None, None]:
"""Handle node retry events."""
self._ensure_workflow_initialized()
with self._database_session() as session:
workflow_node_execution = self._workflow_cycle_manager.handle_workflow_node_execution_retried(
workflow_execution_id=self._workflow_run_id,
event=event,
)
response = self._workflow_response_converter.workflow_node_retry_to_stream_response(
event=event,
task_id=self._application_generate_entity.task_id,
workflow_node_execution=workflow_node_execution,
)
if response:
yield response
def _handle_node_started_event(
self, event: QueueNodeStartedEvent, **kwargs
) -> Generator[StreamResponse, None, None]:
"""Handle node started events."""
self._ensure_workflow_initialized()
workflow_node_execution = self._workflow_cycle_manager.handle_node_execution_start(
workflow_execution_id=self._workflow_run_id, event=event
)
node_start_response = self._workflow_response_converter.workflow_node_start_to_stream_response(
event=event,
task_id=self._application_generate_entity.task_id,
workflow_node_execution=workflow_node_execution,
)
if node_start_response:
yield node_start_response
def _handle_node_succeeded_event(
self, event: QueueNodeSucceededEvent, **kwargs
) -> Generator[StreamResponse, None, None]:
"""Handle node succeeded events."""
workflow_node_execution = self._workflow_cycle_manager.handle_workflow_node_execution_success(event=event)
node_success_response = self._workflow_response_converter.workflow_node_finish_to_stream_response(
event=event,
task_id=self._application_generate_entity.task_id,
workflow_node_execution=workflow_node_execution,
)
self._save_output_for_event(event, workflow_node_execution.id)
if node_success_response:
yield node_success_response
def _handle_node_failed_events(
self, self,
tts_publisher: Optional[AppGeneratorTTSPublisher] = None, event: Union[
trace_manager: Optional[TraceQueueManager] = None, QueueNodeFailedEvent, QueueNodeInIterationFailedEvent, QueueNodeInLoopFailedEvent, QueueNodeExceptionEvent
],
**kwargs,
) -> Generator[StreamResponse, None, None]: ) -> Generator[StreamResponse, None, None]:
""" """Handle various node failure events."""
Process stream response. workflow_node_execution = self._workflow_cycle_manager.handle_workflow_node_execution_failed(
:return: event=event,
""" )
graph_runtime_state = None node_failed_response = self._workflow_response_converter.workflow_node_finish_to_stream_response(
event=event,
task_id=self._application_generate_entity.task_id,
workflow_node_execution=workflow_node_execution,
)
for queue_message in self._base_task_pipeline._queue_manager.listen(): if isinstance(event, QueueNodeExceptionEvent):
event = queue_message.event self._save_output_for_event(event, workflow_node_execution.id)
if isinstance(event, QueuePingEvent): if node_failed_response:
yield self._base_task_pipeline._ping_stream_response() yield node_failed_response
elif isinstance(event, QueueErrorEvent):
err = self._base_task_pipeline._handle_error(event=event)
yield self._base_task_pipeline._error_to_stream_response(err)
break
elif isinstance(event, QueueWorkflowStartedEvent):
# override graph runtime state
graph_runtime_state = event.graph_runtime_state
# init workflow run
workflow_execution = self._workflow_cycle_manager.handle_workflow_run_start()
self._workflow_run_id = workflow_execution.id_
start_resp = self._workflow_response_converter.workflow_start_to_stream_response(
task_id=self._application_generate_entity.task_id,
workflow_execution=workflow_execution,
)
yield start_resp def _handle_parallel_branch_started_event(
elif isinstance( self, event: QueueParallelBranchRunStartedEvent, **kwargs
event, ) -> Generator[StreamResponse, None, None]:
QueueNodeRetryEvent, """Handle parallel branch started events."""
): self._ensure_workflow_initialized()
if not self._workflow_run_id:
raise ValueError("workflow run not initialized.")
with Session(db.engine, expire_on_commit=False) as session:
workflow_node_execution = self._workflow_cycle_manager.handle_workflow_node_execution_retried(
workflow_execution_id=self._workflow_run_id,
event=event,
)
response = self._workflow_response_converter.workflow_node_retry_to_stream_response(
event=event,
task_id=self._application_generate_entity.task_id,
workflow_node_execution=workflow_node_execution,
)
session.commit()
if response: parallel_start_resp = self._workflow_response_converter.workflow_parallel_branch_start_to_stream_response(
yield response task_id=self._application_generate_entity.task_id,
elif isinstance(event, QueueNodeStartedEvent): workflow_execution_id=self._workflow_run_id,
if not self._workflow_run_id: event=event,
raise ValueError("workflow run not initialized.") )
yield parallel_start_resp
workflow_node_execution = self._workflow_cycle_manager.handle_node_execution_start( def _handle_parallel_branch_finished_events(
workflow_execution_id=self._workflow_run_id, event=event self, event: Union[QueueParallelBranchRunSucceededEvent, QueueParallelBranchRunFailedEvent], **kwargs
) ) -> Generator[StreamResponse, None, None]:
node_start_response = self._workflow_response_converter.workflow_node_start_to_stream_response( """Handle parallel branch finished events."""
event=event, self._ensure_workflow_initialized()
task_id=self._application_generate_entity.task_id,
workflow_node_execution=workflow_node_execution,
)
if node_start_response: parallel_finish_resp = self._workflow_response_converter.workflow_parallel_branch_finished_to_stream_response(
yield node_start_response task_id=self._application_generate_entity.task_id,
elif isinstance(event, QueueNodeSucceededEvent): workflow_execution_id=self._workflow_run_id,
workflow_node_execution = self._workflow_cycle_manager.handle_workflow_node_execution_success( event=event,
event=event )
) yield parallel_finish_resp
node_success_response = self._workflow_response_converter.workflow_node_finish_to_stream_response(
event=event,
task_id=self._application_generate_entity.task_id,
workflow_node_execution=workflow_node_execution,
)
self._save_output_for_event(event, workflow_node_execution.id) def _handle_iteration_start_event(
self, event: QueueIterationStartEvent, **kwargs
) -> Generator[StreamResponse, None, None]:
"""Handle iteration start events."""
self._ensure_workflow_initialized()
if node_success_response: iter_start_resp = self._workflow_response_converter.workflow_iteration_start_to_stream_response(
yield node_success_response task_id=self._application_generate_entity.task_id,
elif isinstance( workflow_execution_id=self._workflow_run_id,
event, event=event,
QueueNodeFailedEvent )
| QueueNodeInIterationFailedEvent yield iter_start_resp
| QueueNodeInLoopFailedEvent
| QueueNodeExceptionEvent,
):
workflow_node_execution = self._workflow_cycle_manager.handle_workflow_node_execution_failed(
event=event,
)
node_failed_response = self._workflow_response_converter.workflow_node_finish_to_stream_response(
event=event,
task_id=self._application_generate_entity.task_id,
workflow_node_execution=workflow_node_execution,
)
if isinstance(event, QueueNodeExceptionEvent):
self._save_output_for_event(event, workflow_node_execution.id)
if node_failed_response: def _handle_iteration_next_event(
yield node_failed_response self, event: QueueIterationNextEvent, **kwargs
) -> Generator[StreamResponse, None, None]:
"""Handle iteration next events."""
self._ensure_workflow_initialized()
elif isinstance(event, QueueParallelBranchRunStartedEvent): iter_next_resp = self._workflow_response_converter.workflow_iteration_next_to_stream_response(
if not self._workflow_run_id: task_id=self._application_generate_entity.task_id,
raise ValueError("workflow run not initialized.") workflow_execution_id=self._workflow_run_id,
event=event,
)
yield iter_next_resp
parallel_start_resp = ( def _handle_iteration_completed_event(
self._workflow_response_converter.workflow_parallel_branch_start_to_stream_response( self, event: QueueIterationCompletedEvent, **kwargs
task_id=self._application_generate_entity.task_id, ) -> Generator[StreamResponse, None, None]:
workflow_execution_id=self._workflow_run_id, """Handle iteration completed events."""
event=event, self._ensure_workflow_initialized()
)
)
yield parallel_start_resp iter_finish_resp = self._workflow_response_converter.workflow_iteration_completed_to_stream_response(
task_id=self._application_generate_entity.task_id,
workflow_execution_id=self._workflow_run_id,
event=event,
)
yield iter_finish_resp
elif isinstance(event, QueueParallelBranchRunSucceededEvent | QueueParallelBranchRunFailedEvent): def _handle_loop_start_event(self, event: QueueLoopStartEvent, **kwargs) -> Generator[StreamResponse, None, None]:
if not self._workflow_run_id: """Handle loop start events."""
raise ValueError("workflow run not initialized.") self._ensure_workflow_initialized()
parallel_finish_resp = ( loop_start_resp = self._workflow_response_converter.workflow_loop_start_to_stream_response(
self._workflow_response_converter.workflow_parallel_branch_finished_to_stream_response( task_id=self._application_generate_entity.task_id,
task_id=self._application_generate_entity.task_id, workflow_execution_id=self._workflow_run_id,
workflow_execution_id=self._workflow_run_id, event=event,
event=event, )
) yield loop_start_resp
)
yield parallel_finish_resp def _handle_loop_next_event(self, event: QueueLoopNextEvent, **kwargs) -> Generator[StreamResponse, None, None]:
"""Handle loop next events."""
self._ensure_workflow_initialized()
elif isinstance(event, QueueIterationStartEvent): loop_next_resp = self._workflow_response_converter.workflow_loop_next_to_stream_response(
if not self._workflow_run_id: task_id=self._application_generate_entity.task_id,
raise ValueError("workflow run not initialized.") workflow_execution_id=self._workflow_run_id,
event=event,
)
yield loop_next_resp
iter_start_resp = self._workflow_response_converter.workflow_iteration_start_to_stream_response( def _handle_loop_completed_event(
task_id=self._application_generate_entity.task_id, self, event: QueueLoopCompletedEvent, **kwargs
workflow_execution_id=self._workflow_run_id, ) -> Generator[StreamResponse, None, None]:
event=event, """Handle loop completed events."""
) self._ensure_workflow_initialized()
yield iter_start_resp loop_finish_resp = self._workflow_response_converter.workflow_loop_completed_to_stream_response(
task_id=self._application_generate_entity.task_id,
workflow_execution_id=self._workflow_run_id,
event=event,
)
yield loop_finish_resp
elif isinstance(event, QueueIterationNextEvent): def _handle_workflow_succeeded_event(
if not self._workflow_run_id: self,
raise ValueError("workflow run not initialized.") event: QueueWorkflowSucceededEvent,
*,
graph_runtime_state: Optional[GraphRuntimeState] = None,
trace_manager: Optional[TraceQueueManager] = None,
**kwargs,
) -> Generator[StreamResponse, None, None]:
"""Handle workflow succeeded events."""
self._ensure_workflow_initialized()
validated_state = self._ensure_graph_runtime_initialized(graph_runtime_state)
with self._database_session() as session:
workflow_execution = self._workflow_cycle_manager.handle_workflow_run_success(
workflow_run_id=self._workflow_run_id,
total_tokens=validated_state.total_tokens,
total_steps=validated_state.node_run_steps,
outputs=event.outputs,
conversation_id=None,
trace_manager=trace_manager,
)
iter_next_resp = self._workflow_response_converter.workflow_iteration_next_to_stream_response( # save workflow app log
task_id=self._application_generate_entity.task_id, self._save_workflow_app_log(session=session, workflow_execution=workflow_execution)
workflow_execution_id=self._workflow_run_id,
event=event,
)
yield iter_next_resp workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response(
session=session,
task_id=self._application_generate_entity.task_id,
workflow_execution=workflow_execution,
)
elif isinstance(event, QueueIterationCompletedEvent): yield workflow_finish_resp
if not self._workflow_run_id:
raise ValueError("workflow run not initialized.")
iter_finish_resp = self._workflow_response_converter.workflow_iteration_completed_to_stream_response( def _handle_workflow_partial_success_event(
task_id=self._application_generate_entity.task_id, self,
workflow_execution_id=self._workflow_run_id, event: QueueWorkflowPartialSuccessEvent,
event=event, *,
) graph_runtime_state: Optional[GraphRuntimeState] = None,
trace_manager: Optional[TraceQueueManager] = None,
**kwargs,
) -> Generator[StreamResponse, None, None]:
"""Handle workflow partial success events."""
self._ensure_workflow_initialized()
validated_state = self._ensure_graph_runtime_initialized(graph_runtime_state)
with self._database_session() as session:
workflow_execution = self._workflow_cycle_manager.handle_workflow_run_partial_success(
workflow_run_id=self._workflow_run_id,
total_tokens=validated_state.total_tokens,
total_steps=validated_state.node_run_steps,
outputs=event.outputs,
exceptions_count=event.exceptions_count,
conversation_id=None,
trace_manager=trace_manager,
)
yield iter_finish_resp # save workflow app log
self._save_workflow_app_log(session=session, workflow_execution=workflow_execution)
elif isinstance(event, QueueLoopStartEvent): workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response(
if not self._workflow_run_id: session=session,
raise ValueError("workflow run not initialized.") task_id=self._application_generate_entity.task_id,
workflow_execution=workflow_execution,
)
loop_start_resp = self._workflow_response_converter.workflow_loop_start_to_stream_response( yield workflow_finish_resp
task_id=self._application_generate_entity.task_id,
workflow_execution_id=self._workflow_run_id,
event=event,
)
yield loop_start_resp def _handle_workflow_failed_and_stop_events(
self,
event: Union[QueueWorkflowFailedEvent, QueueStopEvent],
*,
graph_runtime_state: Optional[GraphRuntimeState] = None,
trace_manager: Optional[TraceQueueManager] = None,
**kwargs,
) -> Generator[StreamResponse, None, None]:
"""Handle workflow failed and stop events."""
self._ensure_workflow_initialized()
validated_state = self._ensure_graph_runtime_initialized(graph_runtime_state)
with self._database_session() as session:
workflow_execution = self._workflow_cycle_manager.handle_workflow_run_failed(
workflow_run_id=self._workflow_run_id,
total_tokens=validated_state.total_tokens,
total_steps=validated_state.node_run_steps,
status=WorkflowExecutionStatus.FAILED
if isinstance(event, QueueWorkflowFailedEvent)
else WorkflowExecutionStatus.STOPPED,
error_message=event.error if isinstance(event, QueueWorkflowFailedEvent) else event.get_stop_reason(),
conversation_id=None,
trace_manager=trace_manager,
exceptions_count=event.exceptions_count if isinstance(event, QueueWorkflowFailedEvent) else 0,
)
elif isinstance(event, QueueLoopNextEvent): # save workflow app log
if not self._workflow_run_id: self._save_workflow_app_log(session=session, workflow_execution=workflow_execution)
raise ValueError("workflow run not initialized.")
loop_next_resp = self._workflow_response_converter.workflow_loop_next_to_stream_response( workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response(
task_id=self._application_generate_entity.task_id, session=session,
workflow_execution_id=self._workflow_run_id, task_id=self._application_generate_entity.task_id,
event=event, workflow_execution=workflow_execution,
) )
yield loop_next_resp yield workflow_finish_resp
elif isinstance(event, QueueLoopCompletedEvent): def _handle_text_chunk_event(
if not self._workflow_run_id: self,
raise ValueError("workflow run not initialized.") event: QueueTextChunkEvent,
*,
tts_publisher: Optional[AppGeneratorTTSPublisher] = None,
queue_message: Optional[Union[WorkflowQueueMessage, MessageQueueMessage]] = None,
**kwargs,
) -> Generator[StreamResponse, None, None]:
"""Handle text chunk events."""
delta_text = event.text
if delta_text is None:
return
loop_finish_resp = self._workflow_response_converter.workflow_loop_completed_to_stream_response( # only publish tts message at text chunk streaming
task_id=self._application_generate_entity.task_id, if tts_publisher and queue_message:
workflow_execution_id=self._workflow_run_id, tts_publisher.publish(queue_message)
event=event,
)
yield loop_finish_resp yield self._text_chunk_to_stream_response(delta_text, from_variable_selector=event.from_variable_selector)
elif isinstance(event, QueueWorkflowSucceededEvent):
if not self._workflow_run_id:
raise ValueError("workflow run not initialized.")
if not graph_runtime_state:
raise ValueError("graph runtime state not initialized.")
with Session(db.engine, expire_on_commit=False) as session:
workflow_execution = self._workflow_cycle_manager.handle_workflow_run_success(
workflow_run_id=self._workflow_run_id,
total_tokens=graph_runtime_state.total_tokens,
total_steps=graph_runtime_state.node_run_steps,
outputs=event.outputs,
conversation_id=None,
trace_manager=trace_manager,
)
# save workflow app log def _handle_agent_log_event(self, event: QueueAgentLogEvent, **kwargs) -> Generator[StreamResponse, None, None]:
self._save_workflow_app_log(session=session, workflow_execution=workflow_execution) """Handle agent log events."""
yield self._workflow_response_converter.handle_agent_log(
task_id=self._application_generate_entity.task_id, event=event
)
workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response( def _get_event_handlers(self) -> dict[type, Callable]:
session=session, """Get mapping of event types to their handlers using fluent pattern."""
task_id=self._application_generate_entity.task_id, return {
workflow_execution=workflow_execution, # Basic events
) QueuePingEvent: self._handle_ping_event,
session.commit() QueueErrorEvent: self._handle_error_event,
QueueTextChunkEvent: self._handle_text_chunk_event,
yield workflow_finish_resp # Workflow events
elif isinstance(event, QueueWorkflowPartialSuccessEvent): QueueWorkflowStartedEvent: self._handle_workflow_started_event,
if not self._workflow_run_id: QueueWorkflowSucceededEvent: self._handle_workflow_succeeded_event,
raise ValueError("workflow run not initialized.") QueueWorkflowPartialSuccessEvent: self._handle_workflow_partial_success_event,
if not graph_runtime_state: # Node events
raise ValueError("graph runtime state not initialized.") QueueNodeRetryEvent: self._handle_node_retry_event,
QueueNodeStartedEvent: self._handle_node_started_event,
with Session(db.engine, expire_on_commit=False) as session: QueueNodeSucceededEvent: self._handle_node_succeeded_event,
workflow_execution = self._workflow_cycle_manager.handle_workflow_run_partial_success( # Parallel branch events
workflow_run_id=self._workflow_run_id, QueueParallelBranchRunStartedEvent: self._handle_parallel_branch_started_event,
total_tokens=graph_runtime_state.total_tokens, # Iteration events
total_steps=graph_runtime_state.node_run_steps, QueueIterationStartEvent: self._handle_iteration_start_event,
outputs=event.outputs, QueueIterationNextEvent: self._handle_iteration_next_event,
exceptions_count=event.exceptions_count, QueueIterationCompletedEvent: self._handle_iteration_completed_event,
conversation_id=None, # Loop events
trace_manager=trace_manager, QueueLoopStartEvent: self._handle_loop_start_event,
) QueueLoopNextEvent: self._handle_loop_next_event,
QueueLoopCompletedEvent: self._handle_loop_completed_event,
# Agent events
QueueAgentLogEvent: self._handle_agent_log_event,
}
def _dispatch_event(
self,
event: Any,
*,
graph_runtime_state: Optional[GraphRuntimeState] = None,
tts_publisher: Optional[AppGeneratorTTSPublisher] = None,
trace_manager: Optional[TraceQueueManager] = None,
queue_message: Optional[Union[WorkflowQueueMessage, MessageQueueMessage]] = None,
) -> Generator[StreamResponse, None, None]:
"""Dispatch events using elegant pattern matching."""
handlers = self._get_event_handlers()
event_type = type(event)
# save workflow app log # Direct handler lookup
self._save_workflow_app_log(session=session, workflow_execution=workflow_execution) if handler := handlers.get(event_type):
yield from handler(
event,
graph_runtime_state=graph_runtime_state,
tts_publisher=tts_publisher,
trace_manager=trace_manager,
queue_message=queue_message,
)
return
workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response( # Handle node failure events with isinstance check
session=session, if isinstance(
task_id=self._application_generate_entity.task_id, event,
workflow_execution=workflow_execution, (
) QueueNodeFailedEvent,
session.commit() QueueNodeInIterationFailedEvent,
QueueNodeInLoopFailedEvent,
yield workflow_finish_resp QueueNodeExceptionEvent,
elif isinstance(event, QueueWorkflowFailedEvent | QueueStopEvent): ),
if not self._workflow_run_id: ):
raise ValueError("workflow run not initialized.") yield from self._handle_node_failed_events(
if not graph_runtime_state: event,
raise ValueError("graph runtime state not initialized.") graph_runtime_state=graph_runtime_state,
tts_publisher=tts_publisher,
with Session(db.engine, expire_on_commit=False) as session: trace_manager=trace_manager,
workflow_execution = self._workflow_cycle_manager.handle_workflow_run_failed( queue_message=queue_message,
workflow_run_id=self._workflow_run_id, )
total_tokens=graph_runtime_state.total_tokens, return
total_steps=graph_runtime_state.node_run_steps,
status=WorkflowExecutionStatus.FAILED
if isinstance(event, QueueWorkflowFailedEvent)
else WorkflowExecutionStatus.STOPPED,
error_message=event.error
if isinstance(event, QueueWorkflowFailedEvent)
else event.get_stop_reason(),
conversation_id=None,
trace_manager=trace_manager,
exceptions_count=event.exceptions_count if isinstance(event, QueueWorkflowFailedEvent) else 0,
)
# save workflow app log # Handle parallel branch finished events with isinstance check
self._save_workflow_app_log(session=session, workflow_execution=workflow_execution) if isinstance(event, (QueueParallelBranchRunSucceededEvent, QueueParallelBranchRunFailedEvent)):
yield from self._handle_parallel_branch_finished_events(
event,
graph_runtime_state=graph_runtime_state,
tts_publisher=tts_publisher,
trace_manager=trace_manager,
queue_message=queue_message,
)
return
workflow_finish_resp = self._workflow_response_converter.workflow_finish_to_stream_response( # Handle workflow failed and stop events with isinstance check
session=session, if isinstance(event, (QueueWorkflowFailedEvent, QueueStopEvent)):
task_id=self._application_generate_entity.task_id, yield from self._handle_workflow_failed_and_stop_events(
workflow_execution=workflow_execution, event,
) graph_runtime_state=graph_runtime_state,
session.commit() tts_publisher=tts_publisher,
trace_manager=trace_manager,
queue_message=queue_message,
)
return
yield workflow_finish_resp # For unhandled events, we continue (original behavior)
elif isinstance(event, QueueTextChunkEvent): return
delta_text = event.text
if delta_text is None:
continue
# only publish tts message at text chunk streaming def _process_stream_response(
if tts_publisher: self,
tts_publisher.publish(queue_message) tts_publisher: Optional[AppGeneratorTTSPublisher] = None,
trace_manager: Optional[TraceQueueManager] = None,
) -> Generator[StreamResponse, None, None]:
"""
Process stream response using elegant Fluent Python patterns.
Maintains exact same functionality as original 44-if-statement version.
"""
# Initialize graph runtime state
graph_runtime_state = None
yield self._text_chunk_to_stream_response( for queue_message in self._base_task_pipeline._queue_manager.listen():
delta_text, from_variable_selector=event.from_variable_selector event = queue_message.event
)
elif isinstance(event, QueueAgentLogEvent): match event:
yield self._workflow_response_converter.handle_agent_log( case QueueWorkflowStartedEvent():
task_id=self._application_generate_entity.task_id, event=event graph_runtime_state = event.graph_runtime_state
) yield from self._handle_workflow_started_event(event)
else:
continue case QueueTextChunkEvent():
yield from self._handle_text_chunk_event(
event, tts_publisher=tts_publisher, queue_message=queue_message
)
case QueueErrorEvent():
yield from self._handle_error_event(event)
break
# Handle all other events through elegant dispatch
case _:
if responses := list(
self._dispatch_event(
event,
graph_runtime_state=graph_runtime_state,
tts_publisher=tts_publisher,
trace_manager=trace_manager,
queue_message=queue_message,
)
):
yield from responses
if tts_publisher: if tts_publisher:
tts_publisher.publish(None) tts_publisher.publish(None)

Loading…
Cancel
Save