diff --git a/api/configs/remote_settings_sources/apollo/utils.py b/api/configs/remote_settings_sources/apollo/utils.py index cff187954d..40731448a0 100644 --- a/api/configs/remote_settings_sources/apollo/utils.py +++ b/api/configs/remote_settings_sources/apollo/utils.py @@ -29,7 +29,7 @@ def no_key_cache_key(namespace: str, key: str) -> str: # Returns whether the obtained value is obtained, and None if it does not -def get_value_from_dict(namespace_cache: dict[str, Any] | None, key: str) -> Any | None: +def get_value_from_dict(namespace_cache: dict[str, Any] | None, key: str) -> Any: if namespace_cache: kv_data = namespace_cache.get(CONFIGURATIONS) if kv_data is None: diff --git a/api/core/app/apps/common/workflow_response_converter.py b/api/core/app/apps/common/workflow_response_converter.py index e4796dd3d0..6dd739429f 100644 --- a/api/core/app/apps/common/workflow_response_converter.py +++ b/api/core/app/apps/common/workflow_response_converter.py @@ -319,7 +319,7 @@ class WorkflowResponseConverter: node_id=event.node_id, node_type=event.node_type.value, title=event.node_title, - outputs=json_converter.to_json_encodable(event.outputs), + outputs=json_converter.to_json_encodable(event.outputs) or {}, created_at=int(time.time()), extras={}, inputs=event.inputs or {}, @@ -328,7 +328,7 @@ class WorkflowResponseConverter: else WorkflowNodeExecutionStatus.FAILED, error=None, elapsed_time=(naive_utc_now() - event.start_at).total_seconds(), - total_tokens=event.metadata.get("total_tokens", 0) if event.metadata else 0, + total_tokens=(lambda x: x if isinstance(x, int) else 0)(event.metadata.get("total_tokens", 0)), execution_metadata=event.metadata, finished_at=int(time.time()), steps=event.steps, @@ -395,7 +395,7 @@ class WorkflowResponseConverter: node_id=event.node_id, node_type=event.node_type.value, title=event.node_title, - outputs=WorkflowRuntimeTypeConverter().to_json_encodable(event.outputs), + outputs=WorkflowRuntimeTypeConverter().to_json_encodable(event.outputs) or {}, created_at=int(time.time()), extras={}, inputs=event.inputs or {}, @@ -404,7 +404,7 @@ class WorkflowResponseConverter: else WorkflowNodeExecutionStatus.FAILED, error=None, elapsed_time=(naive_utc_now() - event.start_at).total_seconds(), - total_tokens=event.metadata.get("total_tokens", 0) if event.metadata else 0, + total_tokens=(lambda x: x if isinstance(x, int) else 0)(event.metadata.get("total_tokens", 0)), execution_metadata=event.metadata, finished_at=int(time.time()), steps=event.steps, diff --git a/api/core/app/apps/workflow_app_runner.py b/api/core/app/apps/workflow_app_runner.py index 9b104cdace..056e03fa14 100644 --- a/api/core/app/apps/workflow_app_runner.py +++ b/api/core/app/apps/workflow_app_runner.py @@ -384,7 +384,6 @@ class WorkflowBasedAppRunner: predecessor_node_id=event.predecessor_node_id, in_iteration_id=event.in_iteration_id, in_loop_id=event.in_loop_id, - parallel_mode_run_id=event.parallel_mode_run_id, inputs=inputs, process_data=process_data, outputs=outputs, @@ -406,7 +405,6 @@ class WorkflowBasedAppRunner: predecessor_node_id=event.predecessor_node_id, in_iteration_id=event.in_iteration_id, in_loop_id=event.in_loop_id, - parallel_mode_run_id=event.parallel_mode_run_id, agent_strategy=event.agent_strategy, provider_type=event.provider_type, provider_id=event.provider_id, diff --git a/api/core/app/entities/queue_entities.py b/api/core/app/entities/queue_entities.py index fc2991f1ea..34bacfbd6c 100644 --- a/api/core/app/entities/queue_entities.py +++ b/api/core/app/entities/queue_entities.py @@ -1,9 +1,9 @@ from collections.abc import Mapping, Sequence from datetime import datetime from enum import Enum, StrEnum -from typing import Any, Optional +from typing import Any -from pydantic import BaseModel +from pydantic import BaseModel, Field from core.model_runtime.entities.llm_entities import LLMResult, LLMResultChunk from core.rag.entities.citation_metadata import RetrievalSourceMetadata @@ -79,9 +79,9 @@ class QueueIterationStartEvent(AppQueueEvent): start_at: datetime node_run_index: int - inputs: Optional[Mapping[str, Any]] = None - predecessor_node_id: Optional[str] = None - metadata: Optional[Mapping[str, Any]] = None + inputs: Mapping[str, object] = Field(default_factory=dict) + predecessor_node_id: str | None = None + metadata: Mapping[str, object] = Field(default_factory=dict) class QueueIterationNextEvent(AppQueueEvent): @@ -97,7 +97,7 @@ class QueueIterationNextEvent(AppQueueEvent): node_type: NodeType node_title: str node_run_index: int - output: Optional[Any] = None # output for the current iteration + output: Any = None # output for the current iteration class QueueIterationCompletedEvent(AppQueueEvent): @@ -114,12 +114,12 @@ class QueueIterationCompletedEvent(AppQueueEvent): start_at: datetime node_run_index: int - inputs: Optional[Mapping[str, Any]] = None - outputs: Optional[Mapping[str, Any]] = None - metadata: Optional[Mapping[str, Any]] = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 - error: Optional[str] = None + error: str | None = None class QueueLoopStartEvent(AppQueueEvent): @@ -132,20 +132,20 @@ class QueueLoopStartEvent(AppQueueEvent): node_id: str node_type: NodeType node_title: str - parallel_id: Optional[str] = None + parallel_id: str | None = None """parallel id if node is in parallel""" - parallel_start_node_id: Optional[str] = None + parallel_start_node_id: str | None = None """parallel start node id if node is in parallel""" - parent_parallel_id: Optional[str] = None + parent_parallel_id: str | None = None """parent parallel id if node is in parallel""" - parent_parallel_start_node_id: Optional[str] = None + parent_parallel_start_node_id: str | None = None """parent parallel start node id if node is in parallel""" start_at: datetime node_run_index: int - inputs: Optional[Mapping[str, Any]] = None - predecessor_node_id: Optional[str] = None - metadata: Optional[Mapping[str, Any]] = None + inputs: Mapping[str, object] = Field(default_factory=dict) + predecessor_node_id: str | None = None + metadata: Mapping[str, object] = Field(default_factory=dict) class QueueLoopNextEvent(AppQueueEvent): @@ -160,18 +160,18 @@ class QueueLoopNextEvent(AppQueueEvent): node_id: str node_type: NodeType node_title: str - parallel_id: Optional[str] = None + parallel_id: str | None = None """parallel id if node is in parallel""" - parallel_start_node_id: Optional[str] = None + parallel_start_node_id: str | None = None """parallel start node id if node is in parallel""" - parent_parallel_id: Optional[str] = None + parent_parallel_id: str | None = None """parent parallel id if node is in parallel""" - parent_parallel_start_node_id: Optional[str] = None + parent_parallel_start_node_id: str | None = None """parent parallel start node id if node is in parallel""" - parallel_mode_run_id: Optional[str] = None + parallel_mode_run_id: str | None = None """iteration run in parallel mode run id""" node_run_index: int - output: Optional[Any] = None # output for the current loop + output: Any = None # output for the current loop class QueueLoopCompletedEvent(AppQueueEvent): @@ -185,23 +185,23 @@ class QueueLoopCompletedEvent(AppQueueEvent): node_id: str node_type: NodeType node_title: str - parallel_id: Optional[str] = None + parallel_id: str | None = None """parallel id if node is in parallel""" - parallel_start_node_id: Optional[str] = None + parallel_start_node_id: str | None = None """parallel start node id if node is in parallel""" - parent_parallel_id: Optional[str] = None + parent_parallel_id: str | None = None """parent parallel id if node is in parallel""" - parent_parallel_start_node_id: Optional[str] = None + parent_parallel_start_node_id: str | None = None """parent parallel start node id if node is in parallel""" start_at: datetime node_run_index: int - inputs: Optional[Mapping[str, Any]] = None - outputs: Optional[Mapping[str, Any]] = None - metadata: Optional[Mapping[str, Any]] = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 - error: Optional[str] = None + error: str | None = None class QueueTextChunkEvent(AppQueueEvent): @@ -211,11 +211,11 @@ class QueueTextChunkEvent(AppQueueEvent): event: QueueEvent = QueueEvent.TEXT_CHUNK text: str - from_variable_selector: Optional[list[str]] = None + from_variable_selector: list[str] | None = None """from variable selector""" - in_iteration_id: Optional[str] = None + in_iteration_id: str | None = None """iteration id if node is in iteration""" - in_loop_id: Optional[str] = None + in_loop_id: str | None = None """loop id if node is in loop""" @@ -252,9 +252,9 @@ class QueueRetrieverResourcesEvent(AppQueueEvent): event: QueueEvent = QueueEvent.RETRIEVER_RESOURCES retriever_resources: Sequence[RetrievalSourceMetadata] - in_iteration_id: Optional[str] = None + in_iteration_id: str | None = None """iteration id if node is in iteration""" - in_loop_id: Optional[str] = None + in_loop_id: str | None = None """loop id if node is in loop""" @@ -273,7 +273,7 @@ class QueueMessageEndEvent(AppQueueEvent): """ event: QueueEvent = QueueEvent.MESSAGE_END - llm_result: Optional[LLMResult] = None + llm_result: LLMResult | None = None class QueueAdvancedChatMessageEndEvent(AppQueueEvent): @@ -299,7 +299,7 @@ class QueueWorkflowSucceededEvent(AppQueueEvent): """ event: QueueEvent = QueueEvent.WORKFLOW_SUCCEEDED - outputs: Optional[dict[str, Any]] = None + outputs: Mapping[str, object] = Field(default_factory=dict) class QueueWorkflowFailedEvent(AppQueueEvent): @@ -319,7 +319,7 @@ class QueueWorkflowPartialSuccessEvent(AppQueueEvent): event: QueueEvent = QueueEvent.WORKFLOW_PARTIAL_SUCCEEDED exceptions_count: int - outputs: Optional[dict[str, Any]] = None + outputs: Mapping[str, object] = Field(default_factory=dict) class QueueNodeStartedEvent(AppQueueEvent): @@ -334,16 +334,16 @@ class QueueNodeStartedEvent(AppQueueEvent): node_title: str node_type: NodeType node_run_index: int = 1 # FIXME(-LAN-): may not used - predecessor_node_id: Optional[str] = None - parallel_id: Optional[str] = None - parallel_start_node_id: Optional[str] = None - parent_parallel_id: Optional[str] = None - parent_parallel_start_node_id: Optional[str] = None - in_iteration_id: Optional[str] = None - in_loop_id: Optional[str] = None + predecessor_node_id: str | None = None + parallel_id: str | None = None + parallel_start_node_id: str | None = None + parent_parallel_id: str | None = None + parent_parallel_start_node_id: str | None = None + in_iteration_id: str | None = None + in_loop_id: str | None = None start_at: datetime - parallel_mode_run_id: Optional[str] = None - agent_strategy: Optional[AgentNodeStrategyInit] = None + parallel_mode_run_id: str | None = None + agent_strategy: AgentNodeStrategyInit | None = None # FIXME(-LAN-): only for ToolNode, need to refactor provider_type: str # should be a core.tools.entities.tool_entities.ToolProviderType @@ -360,26 +360,26 @@ class QueueNodeSucceededEvent(AppQueueEvent): node_execution_id: str node_id: str node_type: NodeType - parallel_id: Optional[str] = None + parallel_id: str | None = None """parallel id if node is in parallel""" - parallel_start_node_id: Optional[str] = None + parallel_start_node_id: str | None = None """parallel start node id if node is in parallel""" - parent_parallel_id: Optional[str] = None + parent_parallel_id: str | None = None """parent parallel id if node is in parallel""" - parent_parallel_start_node_id: Optional[str] = None + parent_parallel_start_node_id: str | None = None """parent parallel start node id if node is in parallel""" - in_iteration_id: Optional[str] = None + in_iteration_id: str | None = None """iteration id if node is in iteration""" - in_loop_id: Optional[str] = None + in_loop_id: str | None = None """loop id if node is in loop""" start_at: datetime - inputs: Optional[Mapping[str, Any]] = None - process_data: Optional[Mapping[str, Any]] = None - outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None + inputs: Mapping[str, object] = Field(default_factory=dict) + process_data: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + execution_metadata: Mapping[WorkflowNodeExecutionMetadataKey, Any] | None = None - error: Optional[str] = None + error: str | None = None class QueueAgentLogEvent(AppQueueEvent): @@ -395,7 +395,7 @@ class QueueAgentLogEvent(AppQueueEvent): error: str | None = None status: str data: Mapping[str, Any] - metadata: Optional[Mapping[str, Any]] = None + metadata: Mapping[str, object] = Field(default_factory=dict) node_id: str @@ -404,10 +404,10 @@ class QueueNodeRetryEvent(QueueNodeStartedEvent): event: QueueEvent = QueueEvent.RETRY - inputs: Optional[Mapping[str, Any]] = None - process_data: Optional[Mapping[str, Any]] = None - outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None + inputs: Mapping[str, object] = Field(default_factory=dict) + process_data: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + execution_metadata: Mapping[WorkflowNodeExecutionMetadataKey, Any] | None = None error: str retry_index: int # retry index @@ -423,24 +423,24 @@ class QueueNodeExceptionEvent(AppQueueEvent): node_execution_id: str node_id: str node_type: NodeType - parallel_id: Optional[str] = None + parallel_id: str | None = None """parallel id if node is in parallel""" - parallel_start_node_id: Optional[str] = None + parallel_start_node_id: str | None = None """parallel start node id if node is in parallel""" - parent_parallel_id: Optional[str] = None + parent_parallel_id: str | None = None """parent parallel id if node is in parallel""" - parent_parallel_start_node_id: Optional[str] = None + parent_parallel_start_node_id: str | None = None """parent parallel start node id if node is in parallel""" - in_iteration_id: Optional[str] = None + in_iteration_id: str | None = None """iteration id if node is in iteration""" - in_loop_id: Optional[str] = None + in_loop_id: str | None = None """loop id if node is in loop""" start_at: datetime - inputs: Optional[Mapping[str, Any]] = None - process_data: Optional[Mapping[str, Any]] = None - outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None + inputs: Mapping[str, object] = Field(default_factory=dict) + process_data: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + execution_metadata: Mapping[WorkflowNodeExecutionMetadataKey, Any] | None = None error: str @@ -455,17 +455,17 @@ class QueueNodeFailedEvent(AppQueueEvent): node_execution_id: str node_id: str node_type: NodeType - parallel_id: Optional[str] = None - in_iteration_id: Optional[str] = None + parallel_id: str | None = None + in_iteration_id: str | None = None """iteration id if node is in iteration""" - in_loop_id: Optional[str] = None + in_loop_id: str | None = None """loop id if node is in loop""" start_at: datetime - inputs: Optional[Mapping[str, Any]] = None - process_data: Optional[Mapping[str, Any]] = None - outputs: Optional[Mapping[str, Any]] = None - execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None + inputs: Mapping[str, object] = Field(default_factory=dict) + process_data: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + execution_metadata: Mapping[WorkflowNodeExecutionMetadataKey, Any] | None = None error: str @@ -494,7 +494,7 @@ class QueueErrorEvent(AppQueueEvent): """ event: QueueEvent = QueueEvent.ERROR - error: Optional[Any] = None + error: Any = None class QueuePingEvent(AppQueueEvent): diff --git a/api/core/app/entities/task_entities.py b/api/core/app/entities/task_entities.py index 86f05e9624..59e4ffb351 100644 --- a/api/core/app/entities/task_entities.py +++ b/api/core/app/entities/task_entities.py @@ -1,6 +1,6 @@ from collections.abc import Mapping, Sequence from enum import Enum -from typing import Any, Optional +from typing import Any from pydantic import BaseModel, ConfigDict, Field @@ -108,7 +108,7 @@ class MessageStreamResponse(StreamResponse): event: StreamEvent = StreamEvent.MESSAGE id: str answer: str - from_variable_selector: Optional[list[str]] = None + from_variable_selector: list[str] | None = None class MessageAudioStreamResponse(StreamResponse): @@ -136,8 +136,8 @@ class MessageEndStreamResponse(StreamResponse): event: StreamEvent = StreamEvent.MESSAGE_END id: str - metadata: dict = Field(default_factory=dict) - files: Optional[Sequence[Mapping[str, Any]]] = None + metadata: Mapping[str, object] = Field(default_factory=dict) + files: Sequence[Mapping[str, Any]] | None = None class MessageFileStreamResponse(StreamResponse): @@ -170,12 +170,12 @@ class AgentThoughtStreamResponse(StreamResponse): event: StreamEvent = StreamEvent.AGENT_THOUGHT id: str position: int - thought: Optional[str] = None - observation: Optional[str] = None - tool: Optional[str] = None - tool_labels: Optional[dict] = None - tool_input: Optional[str] = None - message_files: Optional[list[str]] = None + thought: str | None = None + observation: str | None = None + tool: str | None = None + tool_labels: Mapping[str, object] = Field(default_factory=dict) + tool_input: str | None = None + message_files: list[str] | None = None class AgentMessageStreamResponse(StreamResponse): @@ -221,16 +221,16 @@ class WorkflowFinishStreamResponse(StreamResponse): id: str workflow_id: str status: str - outputs: Optional[Mapping[str, Any]] = None - error: Optional[str] = None + outputs: Mapping[str, Any] | None = None + error: str | None = None elapsed_time: float total_tokens: int total_steps: int - created_by: Optional[dict] = None + created_by: Mapping[str, object] = Field(default_factory=dict) created_at: int finished_at: int - exceptions_count: Optional[int] = 0 - files: Optional[Sequence[Mapping[str, Any]]] = [] + exceptions_count: int | None = 0 + files: Sequence[Mapping[str, Any]] | None = [] event: StreamEvent = StreamEvent.WORKFLOW_FINISHED workflow_run_id: str @@ -252,18 +252,18 @@ class NodeStartStreamResponse(StreamResponse): node_type: str title: str index: int - predecessor_node_id: Optional[str] = None - inputs: Optional[Mapping[str, Any]] = None + predecessor_node_id: str | None = None + inputs: Mapping[str, Any] | None = None created_at: int - extras: dict = Field(default_factory=dict) - parallel_id: Optional[str] = None - parallel_start_node_id: Optional[str] = None - parent_parallel_id: Optional[str] = None - parent_parallel_start_node_id: Optional[str] = None - iteration_id: Optional[str] = None - loop_id: Optional[str] = None - parallel_run_id: Optional[str] = None - agent_strategy: Optional[AgentNodeStrategyInit] = None + extras: dict[str, object] = Field(default_factory=dict) + parallel_id: str | None = None + parallel_start_node_id: str | None = None + parent_parallel_id: str | None = None + parent_parallel_start_node_id: str | None = None + iteration_id: str | None = None + loop_id: str | None = None + parallel_run_id: str | None = None + agent_strategy: AgentNodeStrategyInit | None = None event: StreamEvent = StreamEvent.NODE_STARTED workflow_run_id: str @@ -309,23 +309,23 @@ class NodeFinishStreamResponse(StreamResponse): node_type: str title: str index: int - predecessor_node_id: Optional[str] = None - inputs: Optional[Mapping[str, Any]] = None - process_data: Optional[Mapping[str, Any]] = None - outputs: Optional[Mapping[str, Any]] = None + predecessor_node_id: str | None = None + inputs: Mapping[str, Any] | None = None + process_data: Mapping[str, Any] | None = None + outputs: Mapping[str, Any] | None = None status: str - error: Optional[str] = None + error: str | None = None elapsed_time: float - execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None + execution_metadata: Mapping[WorkflowNodeExecutionMetadataKey, Any] | None = None created_at: int finished_at: int - files: Optional[Sequence[Mapping[str, Any]]] = [] - parallel_id: Optional[str] = None - parallel_start_node_id: Optional[str] = None - parent_parallel_id: Optional[str] = None - parent_parallel_start_node_id: Optional[str] = None - iteration_id: Optional[str] = None - loop_id: Optional[str] = None + files: Sequence[Mapping[str, Any]] | None = [] + parallel_id: str | None = None + parallel_start_node_id: str | None = None + parent_parallel_id: str | None = None + parent_parallel_start_node_id: str | None = None + iteration_id: str | None = None + loop_id: str | None = None event: StreamEvent = StreamEvent.NODE_FINISHED workflow_run_id: str @@ -378,23 +378,23 @@ class NodeRetryStreamResponse(StreamResponse): node_type: str title: str index: int - predecessor_node_id: Optional[str] = None - inputs: Optional[Mapping[str, Any]] = None - process_data: Optional[Mapping[str, Any]] = None - outputs: Optional[Mapping[str, Any]] = None + predecessor_node_id: str | None = None + inputs: Mapping[str, Any] | None = None + process_data: Mapping[str, Any] | None = None + outputs: Mapping[str, Any] | None = None status: str - error: Optional[str] = None + error: str | None = None elapsed_time: float - execution_metadata: Optional[Mapping[WorkflowNodeExecutionMetadataKey, Any]] = None + execution_metadata: Mapping[WorkflowNodeExecutionMetadataKey, Any] | None = None created_at: int finished_at: int - files: Optional[Sequence[Mapping[str, Any]]] = [] - parallel_id: Optional[str] = None - parallel_start_node_id: Optional[str] = None - parent_parallel_id: Optional[str] = None - parent_parallel_start_node_id: Optional[str] = None - iteration_id: Optional[str] = None - loop_id: Optional[str] = None + files: Sequence[Mapping[str, Any]] | None = [] + parallel_id: str | None = None + parallel_start_node_id: str | None = None + parent_parallel_id: str | None = None + parent_parallel_start_node_id: str | None = None + iteration_id: str | None = None + loop_id: str | None = None retry_index: int = 0 event: StreamEvent = StreamEvent.NODE_RETRY @@ -449,9 +449,9 @@ class IterationNodeStartStreamResponse(StreamResponse): node_type: str title: str created_at: int - extras: dict = Field(default_factory=dict) - metadata: Mapping = {} - inputs: Mapping = {} + extras: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) + inputs: Mapping[str, object] = Field(default_factory=dict) event: StreamEvent = StreamEvent.ITERATION_STARTED workflow_run_id: str @@ -474,7 +474,7 @@ class IterationNodeNextStreamResponse(StreamResponse): title: str index: int created_at: int - extras: dict = Field(default_factory=dict) + extras: Mapping[str, object] = Field(default_factory=dict) event: StreamEvent = StreamEvent.ITERATION_NEXT workflow_run_id: str @@ -495,15 +495,15 @@ class IterationNodeCompletedStreamResponse(StreamResponse): node_id: str node_type: str title: str - outputs: Optional[Mapping] = None + outputs: Mapping[str, object] = Field(default_factory=dict) created_at: int - extras: Optional[dict] = None - inputs: Optional[Mapping] = None + extras: Mapping[str, object] = Field(default_factory=dict) + inputs: Mapping[str, object] = Field(default_factory=dict) status: WorkflowNodeExecutionStatus - error: Optional[str] = None + error: str | None = None elapsed_time: float total_tokens: int - execution_metadata: Optional[Mapping] = None + execution_metadata: Mapping[str, object] = Field(default_factory=dict) finished_at: int steps: int @@ -527,11 +527,11 @@ class LoopNodeStartStreamResponse(StreamResponse): node_type: str title: str created_at: int - extras: dict = Field(default_factory=dict) - metadata: Mapping = {} - inputs: Mapping = {} - parallel_id: Optional[str] = None - parallel_start_node_id: Optional[str] = None + extras: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) + inputs: Mapping[str, object] = Field(default_factory=dict) + parallel_id: str | None = None + parallel_start_node_id: str | None = None event: StreamEvent = StreamEvent.LOOP_STARTED workflow_run_id: str @@ -554,11 +554,11 @@ class LoopNodeNextStreamResponse(StreamResponse): title: str index: int created_at: int - pre_loop_output: Optional[Any] = None - extras: dict = Field(default_factory=dict) - parallel_id: Optional[str] = None - parallel_start_node_id: Optional[str] = None - parallel_mode_run_id: Optional[str] = None + pre_loop_output: Any = None + extras: Mapping[str, object] = Field(default_factory=dict) + parallel_id: str | None = None + parallel_start_node_id: str | None = None + parallel_mode_run_id: str | None = None event: StreamEvent = StreamEvent.LOOP_NEXT workflow_run_id: str @@ -579,19 +579,19 @@ class LoopNodeCompletedStreamResponse(StreamResponse): node_id: str node_type: str title: str - outputs: Optional[Mapping] = None + outputs: Mapping[str, object] = Field(default_factory=dict) created_at: int - extras: Optional[dict] = None - inputs: Optional[Mapping] = None + extras: Mapping[str, object] = Field(default_factory=dict) + inputs: Mapping[str, object] = Field(default_factory=dict) status: WorkflowNodeExecutionStatus - error: Optional[str] = None + error: str | None = None elapsed_time: float total_tokens: int - execution_metadata: Optional[Mapping] = None + execution_metadata: Mapping[str, object] = Field(default_factory=dict) finished_at: int steps: int - parallel_id: Optional[str] = None - parallel_start_node_id: Optional[str] = None + parallel_id: str | None = None + parallel_start_node_id: str | None = None event: StreamEvent = StreamEvent.LOOP_COMPLETED workflow_run_id: str @@ -609,7 +609,7 @@ class TextChunkStreamResponse(StreamResponse): """ text: str - from_variable_selector: Optional[list[str]] = None + from_variable_selector: list[str] | None = None event: StreamEvent = StreamEvent.TEXT_CHUNK data: Data @@ -671,7 +671,7 @@ class WorkflowAppStreamResponse(AppStreamResponse): WorkflowAppStreamResponse entity """ - workflow_run_id: Optional[str] = None + workflow_run_id: str | None = None class AppBlockingResponse(BaseModel): @@ -697,7 +697,7 @@ class ChatbotAppBlockingResponse(AppBlockingResponse): conversation_id: str message_id: str answer: str - metadata: dict = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) created_at: int data: Data @@ -717,7 +717,7 @@ class CompletionAppBlockingResponse(AppBlockingResponse): mode: str message_id: str answer: str - metadata: dict = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) created_at: int data: Data @@ -736,8 +736,8 @@ class WorkflowAppBlockingResponse(AppBlockingResponse): id: str workflow_id: str status: str - outputs: Optional[Mapping[str, Any]] = None - error: Optional[str] = None + outputs: Mapping[str, Any] | None = None + error: str | None = None elapsed_time: float total_tokens: int total_steps: int @@ -765,7 +765,7 @@ class AgentLogStreamResponse(StreamResponse): error: str | None = None status: str data: Mapping[str, Any] - metadata: Optional[Mapping[str, Any]] = None + metadata: Mapping[str, object] = Field(default_factory=dict) node_id: str event: StreamEvent = StreamEvent.AGENT_LOG diff --git a/api/core/base/tts/app_generator_tts_publisher.py b/api/core/base/tts/app_generator_tts_publisher.py index 89190c36cc..1e60e14e34 100644 --- a/api/core/base/tts/app_generator_tts_publisher.py +++ b/api/core/base/tts/app_generator_tts_publisher.py @@ -110,7 +110,9 @@ class AppGeneratorTTSPublisher: elif isinstance(message.event, QueueNodeSucceededEvent): if message.event.outputs is None: continue - self.msg_text += message.event.outputs.get("output", "") + output = message.event.outputs.get("output", "") + if isinstance(output, str): + self.msg_text += output self.last_message = message sentence_arr, text_tmp = self._extract_sentence(self.msg_text) if len(sentence_arr) >= min(self.max_sentence, 7): @@ -120,7 +122,7 @@ class AppGeneratorTTSPublisher: _invoice_tts, text_content, self.model_instance, self.tenant_id, self.voice ) future_queue.put(futures_result) - if text_tmp: + if isinstance(text_tmp, str): self.msg_text = text_tmp else: self.msg_text = "" diff --git a/api/core/mcp/types.py b/api/core/mcp/types.py index a2c3157b3b..e939edade5 100644 --- a/api/core/mcp/types.py +++ b/api/core/mcp/types.py @@ -161,7 +161,7 @@ class ErrorData(BaseModel): sentence. """ - data: Any | None = None + data: Any = None """ Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.). diff --git a/api/core/rag/entities/citation_metadata.py b/api/core/rag/entities/citation_metadata.py index 00120425c9..aca879df7d 100644 --- a/api/core/rag/entities/citation_metadata.py +++ b/api/core/rag/entities/citation_metadata.py @@ -1,23 +1,23 @@ -from typing import Any, Optional +from typing import Any from pydantic import BaseModel class RetrievalSourceMetadata(BaseModel): - position: Optional[int] = None - dataset_id: Optional[str] = None - dataset_name: Optional[str] = None - document_id: Optional[str] = None - document_name: Optional[str] = None - data_source_type: Optional[str] = None - segment_id: Optional[str] = None - retriever_from: Optional[str] = None - score: Optional[float] = None - hit_count: Optional[int] = None - word_count: Optional[int] = None - segment_position: Optional[int] = None - index_node_hash: Optional[str] = None - content: Optional[str] = None - page: Optional[int] = None - doc_metadata: Optional[dict[str, Any]] = None - title: Optional[str] = None + position: int | None = None + dataset_id: str | None = None + dataset_name: str | None = None + document_id: str | None = None + document_name: str | None = None + data_source_type: str | None = None + segment_id: str | None = None + retriever_from: str | None = None + score: float | None = None + hit_count: int | None = None + word_count: int | None = None + segment_position: int | None = None + index_node_hash: str | None = None + content: str | None = None + page: int | None = None + doc_metadata: dict[str, Any] | None = None + title: str | None = None diff --git a/api/core/tools/entities/api_entities.py b/api/core/tools/entities/api_entities.py index ca3be26ff9..00c4ab9dd7 100644 --- a/api/core/tools/entities/api_entities.py +++ b/api/core/tools/entities/api_entities.py @@ -1,5 +1,6 @@ +from collections.abc import Mapping from datetime import datetime -from typing import Any, Literal, Optional +from typing import Any, Literal from pydantic import BaseModel, Field, field_validator @@ -14,12 +15,12 @@ class ToolApiEntity(BaseModel): name: str # identifier label: I18nObject # label description: I18nObject - parameters: Optional[list[ToolParameter]] = None + parameters: list[ToolParameter] | None = None labels: list[str] = Field(default_factory=list) - output_schema: Optional[dict] = None + output_schema: Mapping[str, object] = Field(default_factory=dict) -ToolProviderTypeApiLiteral = Optional[Literal["builtin", "api", "workflow", "mcp"]] +ToolProviderTypeApiLiteral = Literal["builtin", "api", "workflow", "mcp"] | None class ToolProviderApiEntity(BaseModel): @@ -27,26 +28,26 @@ class ToolProviderApiEntity(BaseModel): author: str name: str # identifier description: I18nObject - icon: str | dict - icon_dark: Optional[str | dict] = Field(default=None, description="The dark icon of the tool") + icon: str | Mapping[str, str] + icon_dark: str | Mapping[str, str] = "" label: I18nObject # label type: ToolProviderType - masked_credentials: Optional[dict] = None - original_credentials: Optional[dict] = None + masked_credentials: Mapping[str, object] = Field(default_factory=dict) + original_credentials: Mapping[str, object] = Field(default_factory=dict) is_team_authorization: bool = False allow_delete: bool = True - plugin_id: Optional[str] = Field(default="", description="The plugin id of the tool") - plugin_unique_identifier: Optional[str] = Field(default="", description="The unique identifier of the tool") - tools: list[ToolApiEntity] = Field(default_factory=list) + plugin_id: str | None = Field(default="", description="The plugin id of the tool") + plugin_unique_identifier: str | None = Field(default="", description="The unique identifier of the tool") + tools: list[ToolApiEntity] = Field(default_factory=list[ToolApiEntity]) labels: list[str] = Field(default_factory=list) # MCP - server_url: Optional[str] = Field(default="", description="The server url of the tool") + server_url: str | None = Field(default="", description="The server url of the tool") updated_at: int = Field(default_factory=lambda: int(datetime.now().timestamp())) - server_identifier: Optional[str] = Field(default="", description="The server identifier of the MCP tool") - timeout: Optional[float] = Field(default=30.0, description="The timeout of the MCP tool") - sse_read_timeout: Optional[float] = Field(default=300.0, description="The SSE read timeout of the MCP tool") - masked_headers: Optional[dict[str, str]] = Field(default=None, description="The masked headers of the MCP tool") - original_headers: Optional[dict[str, str]] = Field(default=None, description="The original headers of the MCP tool") + server_identifier: str | None = Field(default="", description="The server identifier of the MCP tool") + timeout: float | None = Field(default=30.0, description="The timeout of the MCP tool") + sse_read_timeout: float | None = Field(default=300.0, description="The SSE read timeout of the MCP tool") + masked_headers: dict[str, str] | None = Field(default=None, description="The masked headers of the MCP tool") + original_headers: dict[str, str] | None = Field(default=None, description="The original headers of the MCP tool") @field_validator("tools", mode="before") @classmethod @@ -105,7 +106,7 @@ class ToolProviderCredentialApiEntity(BaseModel): is_default: bool = Field( default=False, description="Whether the credential is the default credential for the provider in the workspace" ) - credentials: dict = Field(description="The credentials of the provider") + credentials: Mapping[str, object] = Field(description="The credentials of the provider", default_factory=dict) class ToolProviderCredentialInfoApiEntity(BaseModel): diff --git a/api/core/tools/entities/tool_entities.py b/api/core/tools/entities/tool_entities.py index 66304b30a5..077949906c 100644 --- a/api/core/tools/entities/tool_entities.py +++ b/api/core/tools/entities/tool_entities.py @@ -3,7 +3,7 @@ import contextlib import enum from collections.abc import Mapping from enum import Enum -from typing import Any, Optional, Union +from typing import Any, Union from pydantic import BaseModel, ConfigDict, Field, ValidationInfo, field_serializer, field_validator, model_validator @@ -183,11 +183,11 @@ class ToolInvokeMessage(BaseModel): id: str label: str = Field(..., description="The label of the log") - parent_id: Optional[str] = Field(default=None, description="Leave empty for root log") - error: Optional[str] = Field(default=None, description="The error message") + parent_id: str | None = Field(default=None, description="Leave empty for root log") + error: str | None = Field(default=None, description="The error message") status: LogStatus = Field(..., description="The status of the log") data: Mapping[str, Any] = Field(..., description="Detailed log data") - metadata: Optional[Mapping[str, Any]] = Field(default=None, description="The metadata of the log") + metadata: Mapping[str, Any] = Field(default_factory=dict, description="The metadata of the log") class RetrieverResourceMessage(BaseModel): retriever_resources: list[RetrievalSourceMetadata] = Field(..., description="retriever resources") @@ -242,7 +242,7 @@ class ToolInvokeMessage(BaseModel): class ToolInvokeMessageBinary(BaseModel): mimetype: str = Field(..., description="The mimetype of the binary") url: str = Field(..., description="The url of the binary") - file_var: Optional[dict[str, Any]] = None + file_var: dict[str, Any] | None = None class ToolParameter(PluginParameter): @@ -286,11 +286,11 @@ class ToolParameter(PluginParameter): LLM = "llm" # will be set by LLM type: ToolParameterType = Field(..., description="The type of the parameter") - human_description: Optional[I18nObject] = Field(default=None, description="The description presented to the user") + human_description: I18nObject | None = Field(default=None, description="The description presented to the user") form: ToolParameterForm = Field(..., description="The form of the parameter, schema/form/llm") - llm_description: Optional[str] = None + llm_description: str | None = None # MCP object and array type parameters use this field to store the schema - input_schema: Optional[dict] = None + input_schema: dict | None = None @classmethod def get_simple_instance( @@ -299,7 +299,7 @@ class ToolParameter(PluginParameter): llm_description: str, typ: ToolParameterType, required: bool, - options: Optional[list[str]] = None, + options: list[str] | None = None, ) -> "ToolParameter": """ get a simple tool parameter @@ -340,9 +340,9 @@ class ToolProviderIdentity(BaseModel): name: str = Field(..., description="The name of the tool") description: I18nObject = Field(..., description="The description of the tool") icon: str = Field(..., description="The icon of the tool") - icon_dark: Optional[str] = Field(default=None, description="The dark icon of the tool") + icon_dark: str | None = Field(default=None, description="The dark icon of the tool") label: I18nObject = Field(..., description="The label of the tool") - tags: Optional[list[ToolLabelEnum]] = Field( + tags: list[ToolLabelEnum] | None = Field( default=[], description="The tags of the tool", ) @@ -353,7 +353,7 @@ class ToolIdentity(BaseModel): name: str = Field(..., description="The name of the tool") label: I18nObject = Field(..., description="The label of the tool") provider: str = Field(..., description="The provider of the tool") - icon: Optional[str] = None + icon: str | None = None class ToolDescription(BaseModel): @@ -363,9 +363,9 @@ class ToolDescription(BaseModel): class ToolEntity(BaseModel): identity: ToolIdentity - parameters: list[ToolParameter] = Field(default_factory=list) - description: Optional[ToolDescription] = None - output_schema: Optional[dict] = None + parameters: list[ToolParameter] = Field(default_factory=list[ToolParameter]) + description: ToolDescription | None = None + output_schema: Mapping[str, object] = Field(default_factory=dict) has_runtime_parameters: bool = Field(default=False, description="Whether the tool has runtime parameters") # pydantic configs @@ -378,21 +378,23 @@ class ToolEntity(BaseModel): class OAuthSchema(BaseModel): - client_schema: list[ProviderConfig] = Field(default_factory=list, description="The schema of the OAuth client") + client_schema: list[ProviderConfig] = Field( + default_factory=list[ProviderConfig], description="The schema of the OAuth client" + ) credentials_schema: list[ProviderConfig] = Field( - default_factory=list, description="The schema of the OAuth credentials" + default_factory=list[ProviderConfig], description="The schema of the OAuth credentials" ) class ToolProviderEntity(BaseModel): identity: ToolProviderIdentity - plugin_id: Optional[str] = None - credentials_schema: list[ProviderConfig] = Field(default_factory=list) - oauth_schema: Optional[OAuthSchema] = None + plugin_id: str | None = None + credentials_schema: list[ProviderConfig] = Field(default_factory=list[ProviderConfig]) + oauth_schema: OAuthSchema | None = None class ToolProviderEntityWithPlugin(ToolProviderEntity): - tools: list[ToolEntity] = Field(default_factory=list) + tools: list[ToolEntity] = Field(default_factory=list[ToolEntity]) class WorkflowToolParameterConfiguration(BaseModel): @@ -411,8 +413,8 @@ class ToolInvokeMeta(BaseModel): """ time_cost: float = Field(..., description="The time cost of the tool invoke") - error: Optional[str] = None - tool_config: Optional[dict] = None + error: str | None = None + tool_config: dict | None = None @classmethod def empty(cls) -> "ToolInvokeMeta": @@ -464,11 +466,11 @@ class ToolSelector(BaseModel): type: ToolParameter.ToolParameterType = Field(..., description="The type of the parameter") required: bool = Field(..., description="Whether the parameter is required") description: str = Field(..., description="The description of the parameter") - default: Optional[Union[int, float, str]] = None - options: Optional[list[PluginParameterOption]] = None + default: Union[int, float, str] | None = None + options: list[PluginParameterOption] | None = None provider_id: str = Field(..., description="The id of the provider") - credential_id: Optional[str] = Field(default=None, description="The id of the credential") + credential_id: str | None = Field(default=None, description="The id of the credential") tool_name: str = Field(..., description="The name of the tool") tool_description: str = Field(..., description="The description of the tool") tool_configuration: Mapping[str, Any] = Field(..., description="Configuration, type form") diff --git a/api/core/tools/mcp_tool/provider.py b/api/core/tools/mcp_tool/provider.py index 5f6eb045ab..1b9c631f81 100644 --- a/api/core/tools/mcp_tool/provider.py +++ b/api/core/tools/mcp_tool/provider.py @@ -72,7 +72,6 @@ class MCPToolProviderController(ToolProviderController): ), llm=remote_mcp_tool.description or "", ), - output_schema=None, has_runtime_parameters=len(remote_mcp_tool.inputSchema) > 0, ) for remote_mcp_tool in remote_mcp_tools diff --git a/api/core/tools/tool_manager.py b/api/core/tools/tool_manager.py index 5c836cfcd2..766e0568c4 100644 --- a/api/core/tools/tool_manager.py +++ b/api/core/tools/tool_manager.py @@ -886,7 +886,7 @@ class ToolManager: ) @classmethod - def generate_workflow_tool_icon_url(cls, tenant_id: str, provider_id: str): + def generate_workflow_tool_icon_url(cls, tenant_id: str, provider_id: str) -> Mapping[str, str]: try: workflow_provider: WorkflowToolProvider | None = ( db.session.query(WorkflowToolProvider) @@ -897,13 +897,13 @@ class ToolManager: if workflow_provider is None: raise ToolProviderNotFoundError(f"workflow provider {provider_id} not found") - icon: dict = json.loads(workflow_provider.icon) + icon = json.loads(workflow_provider.icon) return icon except Exception: return {"background": "#252525", "content": "\ud83d\ude01"} @classmethod - def generate_api_tool_icon_url(cls, tenant_id: str, provider_id: str): + def generate_api_tool_icon_url(cls, tenant_id: str, provider_id: str) -> Mapping[str, str]: try: api_provider: ApiToolProvider | None = ( db.session.query(ApiToolProvider) @@ -914,13 +914,13 @@ class ToolManager: if api_provider is None: raise ToolProviderNotFoundError(f"api provider {provider_id} not found") - icon: dict = json.loads(api_provider.icon) + icon = json.loads(api_provider.icon) return icon except Exception: return {"background": "#252525", "content": "\ud83d\ude01"} @classmethod - def generate_mcp_tool_icon_url(cls, tenant_id: str, provider_id: str) -> dict[str, str] | str: + def generate_mcp_tool_icon_url(cls, tenant_id: str, provider_id: str) -> Mapping[str, str] | str: try: mcp_provider: MCPToolProvider | None = ( db.session.query(MCPToolProvider) @@ -941,7 +941,7 @@ class ToolManager: tenant_id: str, provider_type: ToolProviderType, provider_id: str, - ) -> Union[str, dict[str, Any]]: + ) -> str | Mapping[str, str]: """ get the tool icon @@ -966,11 +966,10 @@ class ToolManager: return cls.generate_workflow_tool_icon_url(tenant_id, provider_id) elif provider_type == ToolProviderType.PLUGIN: provider = ToolManager.get_plugin_provider(provider_id, tenant_id) - if isinstance(provider, PluginToolProviderController): - try: - return cls.generate_plugin_tool_icon_url(tenant_id, provider.entity.identity.icon) - except Exception: - return {"background": "#252525", "content": "\ud83d\ude01"} + try: + return cls.generate_plugin_tool_icon_url(tenant_id, provider.entity.identity.icon) + except Exception: + return {"background": "#252525", "content": "\ud83d\ude01"} raise ValueError(f"plugin provider {provider_id} not found") elif provider_type == ToolProviderType.MCP: return cls.generate_mcp_tool_icon_url(tenant_id, provider_id) diff --git a/api/core/workflow/graph_events/agent.py b/api/core/workflow/graph_events/agent.py index 67d94d25eb..759fe3a71c 100644 --- a/api/core/workflow/graph_events/agent.py +++ b/api/core/workflow/graph_events/agent.py @@ -14,4 +14,4 @@ class NodeRunAgentLogEvent(GraphAgentNodeEventBase): error: str | None = Field(..., description="error") status: str = Field(..., description="status") data: Mapping[str, Any] = Field(..., description="data") - metadata: Mapping[str, Any] | None = Field(default=None, description="metadata") + metadata: Mapping[str, object] = Field(default_factory=dict) diff --git a/api/core/workflow/graph_events/graph.py b/api/core/workflow/graph_events/graph.py index 4f7e886519..5d13833faa 100644 --- a/api/core/workflow/graph_events/graph.py +++ b/api/core/workflow/graph_events/graph.py @@ -1,5 +1,3 @@ -from typing import Any - from pydantic import Field from core.workflow.graph_events import BaseGraphEvent @@ -10,7 +8,7 @@ class GraphRunStartedEvent(BaseGraphEvent): class GraphRunSucceededEvent(BaseGraphEvent): - outputs: dict[str, Any] | None = None + outputs: dict[str, object] = Field(default_factory=dict) class GraphRunFailedEvent(BaseGraphEvent): @@ -20,11 +18,11 @@ class GraphRunFailedEvent(BaseGraphEvent): class GraphRunPartialSucceededEvent(BaseGraphEvent): exceptions_count: int = Field(..., description="exception count") - outputs: dict[str, Any] | None = None + outputs: dict[str, object] = Field(default_factory=dict) class GraphRunAbortedEvent(BaseGraphEvent): """Event emitted when a graph run is aborted by user command.""" reason: str | None = Field(default=None, description="reason for abort") - outputs: dict[str, Any] | None = Field(default=None, description="partial outputs if any") + outputs: dict[str, object] = Field(default_factory=dict, description="partial outputs if any") diff --git a/api/core/workflow/graph_events/iteration.py b/api/core/workflow/graph_events/iteration.py index 3d507dbe46..28627395fd 100644 --- a/api/core/workflow/graph_events/iteration.py +++ b/api/core/workflow/graph_events/iteration.py @@ -10,8 +10,8 @@ from .base import GraphNodeEventBase class NodeRunIterationStartedEvent(GraphNodeEventBase): node_title: str start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) predecessor_node_id: str | None = None @@ -24,17 +24,17 @@ class NodeRunIterationNextEvent(GraphNodeEventBase): class NodeRunIterationSucceededEvent(GraphNodeEventBase): node_title: str start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - outputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 class NodeRunIterationFailedEvent(GraphNodeEventBase): node_title: str start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - outputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 error: str = Field(..., description="failed reason") diff --git a/api/core/workflow/graph_events/loop.py b/api/core/workflow/graph_events/loop.py index c0b540949b..7cdc5427e2 100644 --- a/api/core/workflow/graph_events/loop.py +++ b/api/core/workflow/graph_events/loop.py @@ -10,8 +10,8 @@ from .base import GraphNodeEventBase class NodeRunLoopStartedEvent(GraphNodeEventBase): node_title: str start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) predecessor_node_id: str | None = None @@ -24,17 +24,17 @@ class NodeRunLoopNextEvent(GraphNodeEventBase): class NodeRunLoopSucceededEvent(GraphNodeEventBase): node_title: str start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - outputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 class NodeRunLoopFailedEvent(GraphNodeEventBase): node_title: str start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - outputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 error: str = Field(..., description="failed reason") diff --git a/api/core/workflow/graph_events/node.py b/api/core/workflow/graph_events/node.py index c6365d39c1..1d35a69c4a 100644 --- a/api/core/workflow/graph_events/node.py +++ b/api/core/workflow/graph_events/node.py @@ -12,7 +12,6 @@ from .base import GraphNodeEventBase class NodeRunStartedEvent(GraphNodeEventBase): node_title: str predecessor_node_id: str | None = None - parallel_mode_run_id: str | None = None agent_strategy: AgentNodeStrategyInit | None = None start_at: datetime = Field(..., description="node start time") diff --git a/api/core/workflow/node_events/agent.py b/api/core/workflow/node_events/agent.py index e5fc46ddea..bf295ec774 100644 --- a/api/core/workflow/node_events/agent.py +++ b/api/core/workflow/node_events/agent.py @@ -14,5 +14,5 @@ class AgentLogEvent(NodeEventBase): error: str | None = Field(..., description="error") status: str = Field(..., description="status") data: Mapping[str, Any] = Field(..., description="data") - metadata: Mapping[str, Any] | None = Field(default=None, description="metadata") + metadata: Mapping[str, Any] = Field(default_factory=dict, description="metadata") node_id: str = Field(..., description="node id") diff --git a/api/core/workflow/node_events/iteration.py b/api/core/workflow/node_events/iteration.py index db0b41a43a..744ddea628 100644 --- a/api/core/workflow/node_events/iteration.py +++ b/api/core/workflow/node_events/iteration.py @@ -9,8 +9,8 @@ from .base import NodeEventBase class IterationStartedEvent(NodeEventBase): start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) predecessor_node_id: str | None = None @@ -21,16 +21,16 @@ class IterationNextEvent(NodeEventBase): class IterationSucceededEvent(NodeEventBase): start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - outputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 class IterationFailedEvent(NodeEventBase): start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - outputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 error: str = Field(..., description="failed reason") diff --git a/api/core/workflow/node_events/loop.py b/api/core/workflow/node_events/loop.py index 4e84fb0061..3ae230f9f6 100644 --- a/api/core/workflow/node_events/loop.py +++ b/api/core/workflow/node_events/loop.py @@ -9,8 +9,8 @@ from .base import NodeEventBase class LoopStartedEvent(NodeEventBase): start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) predecessor_node_id: str | None = None @@ -21,16 +21,16 @@ class LoopNextEvent(NodeEventBase): class LoopSucceededEvent(NodeEventBase): start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - outputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 class LoopFailedEvent(NodeEventBase): start_at: datetime = Field(..., description="start at") - inputs: Mapping[str, Any] | None = None - outputs: Mapping[str, Any] | None = None - metadata: Mapping[str, Any] | None = None + inputs: Mapping[str, object] = Field(default_factory=dict) + outputs: Mapping[str, object] = Field(default_factory=dict) + metadata: Mapping[str, object] = Field(default_factory=dict) steps: int = 0 error: str = Field(..., description="failed reason") diff --git a/api/core/workflow/nodes/base/node.py b/api/core/workflow/nodes/base/node.py index de6f4152c6..ce089003cf 100644 --- a/api/core/workflow/nodes/base/node.py +++ b/api/core/workflow/nodes/base/node.py @@ -2,12 +2,12 @@ import logging from abc import abstractmethod from collections.abc import Generator, Mapping, Sequence from functools import singledispatchmethod -from typing import TYPE_CHECKING, Any, ClassVar +from typing import Any, ClassVar from uuid import uuid4 from core.app.entities.app_invoke_entities import InvokeFrom -from core.workflow.entities import AgentNodeStrategyInit -from core.workflow.enums import NodeExecutionType, NodeState, NodeType, WorkflowNodeExecutionStatus +from core.workflow.entities import AgentNodeStrategyInit, GraphInitParams, GraphRuntimeState +from core.workflow.enums import ErrorStrategy, NodeExecutionType, NodeState, NodeType, WorkflowNodeExecutionStatus from core.workflow.graph_events import ( GraphNodeEventBase, NodeRunAgentLogEvent, @@ -46,11 +46,6 @@ from models.enums import UserFrom from .entities import BaseNodeData, RetryConfig -if TYPE_CHECKING: - from core.workflow.entities import GraphInitParams, GraphRuntimeState - from core.workflow.enums import ErrorStrategy, NodeType - from core.workflow.node_events import NodeRunResult - logger = logging.getLogger(__name__) diff --git a/api/models/model.py b/api/models/model.py index 58a75c355c..c479bb666b 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -1138,7 +1138,7 @@ class Message(Base): ) @property - def retriever_resources(self) -> Any | list[Any]: + def retriever_resources(self) -> Any: return self.message_metadata_dict.get("retriever_resources") if self.message_metadata else [] @property diff --git a/api/models/tools.py b/api/models/tools.py index 277a9d032c..545c29357d 100644 --- a/api/models/tools.py +++ b/api/models/tools.py @@ -1,4 +1,5 @@ import json +from collections.abc import Mapping from datetime import datetime from typing import TYPE_CHECKING, Any, Optional, cast from urllib.parse import urlparse @@ -314,11 +315,11 @@ class MCPToolProvider(Base): return [MCPTool(**tool) for tool in json.loads(self.tools)] @property - def provider_icon(self) -> dict[str, str] | str: + def provider_icon(self) -> Mapping[str, str] | str: from core.file import helpers as file_helpers try: - return cast(dict[str, str], json.loads(self.icon)) + return json.loads(self.icon) except json.JSONDecodeError: return file_helpers.get_signed_file_url(self.icon) diff --git a/api/services/tools/tools_transform_service.py b/api/services/tools/tools_transform_service.py index f5fc7f951f..49d3fd57ad 100644 --- a/api/services/tools/tools_transform_service.py +++ b/api/services/tools/tools_transform_service.py @@ -1,6 +1,7 @@ import json import logging -from typing import Any, Optional, Union, cast +from collections.abc import Mapping +from typing import Any, Union from yarl import URL @@ -38,7 +39,9 @@ class ToolTransformService: return str(url_prefix % {"tenant_id": tenant_id, "filename": filename}) @classmethod - def get_tool_provider_icon_url(cls, provider_type: str, provider_name: str, icon: str | dict) -> Union[str, dict]: + def get_tool_provider_icon_url( + cls, provider_type: str, provider_name: str, icon: str | Mapping[str, str] + ) -> str | Mapping[str, str]: """ get tool provider icon url """ @@ -51,7 +54,7 @@ class ToolTransformService: elif provider_type in {ToolProviderType.API.value, ToolProviderType.WORKFLOW.value}: try: if isinstance(icon, str): - return cast(dict, json.loads(icon)) + return json.loads(icon) return icon except Exception: return {"background": "#252525", "content": "\ud83d\ude01"} @@ -94,7 +97,7 @@ class ToolTransformService: def builtin_provider_to_user_provider( cls, provider_controller: BuiltinToolProviderController | PluginToolProviderController, - db_provider: Optional[BuiltinToolProvider], + db_provider: BuiltinToolProvider | None, decrypt_credentials: bool = True, ) -> ToolProviderApiEntity: """ @@ -106,7 +109,7 @@ class ToolTransformService: name=provider_controller.entity.identity.name, description=provider_controller.entity.identity.description, icon=provider_controller.entity.identity.icon, - icon_dark=provider_controller.entity.identity.icon_dark, + icon_dark=provider_controller.entity.identity.icon_dark or "", label=provider_controller.entity.identity.label, type=ToolProviderType.BUILT_IN, masked_credentials={}, @@ -128,9 +131,10 @@ class ToolTransformService: ) } + masked_creds = {} for name in schema: - if result.masked_credentials: - result.masked_credentials[name] = "" + masked_creds[name] = "" + result.masked_credentials = masked_creds # check if the provider need credentials if not provider_controller.need_credentials: @@ -208,7 +212,7 @@ class ToolTransformService: name=provider_controller.entity.identity.name, description=provider_controller.entity.identity.description, icon=provider_controller.entity.identity.icon, - icon_dark=provider_controller.entity.identity.icon_dark, + icon_dark=provider_controller.entity.identity.icon_dark or "", label=provider_controller.entity.identity.label, type=ToolProviderType.WORKFLOW, masked_credentials={}, @@ -321,7 +325,7 @@ class ToolTransformService: @staticmethod def convert_tool_entity_to_api_entity( - tool: Union[ApiToolBundle, WorkflowTool, Tool], + tool: ApiToolBundle | WorkflowTool | Tool, tenant_id: str, labels: list[str] | None = None, ) -> ToolApiEntity: @@ -375,7 +379,7 @@ class ToolTransformService: parameters=merged_parameters, labels=labels or [], ) - elif isinstance(tool, ApiToolBundle): + else: return ToolApiEntity( author=tool.author, name=tool.operation_id or "", @@ -384,9 +388,6 @@ class ToolTransformService: parameters=tool.parameters, labels=labels or [], ) - else: - # Handle WorkflowTool case - raise ValueError(f"Unsupported tool type: {type(tool)}") @staticmethod def convert_builtin_provider_to_credential_entity( diff --git a/api/tests/unit_tests/core/tools/workflow_as_tool/test_tool.py b/api/tests/unit_tests/core/tools/workflow_as_tool/test_tool.py index 5348f729f9..17e3ebeea0 100644 --- a/api/tests/unit_tests/core/tools/workflow_as_tool/test_tool.py +++ b/api/tests/unit_tests/core/tools/workflow_as_tool/test_tool.py @@ -17,7 +17,6 @@ def test_workflow_tool_should_raise_tool_invoke_error_when_result_has_error_fiel identity=ToolIdentity(author="test", name="test tool", label=I18nObject(en_US="test tool"), provider="test"), parameters=[], description=None, - output_schema=None, has_runtime_parameters=False, ) runtime = ToolRuntime(tenant_id="test_tool", invoke_from=InvokeFrom.EXPLORE)