diff --git a/lib/crewai/src/crewai/events/event_types.py b/lib/crewai/src/crewai/events/event_types.py index 5fca4bd7d..ecd6dbea4 100644 --- a/lib/crewai/src/crewai/events/event_types.py +++ b/lib/crewai/src/crewai/events/event_types.py @@ -1,3 +1,7 @@ +from typing import Annotated + +from pydantic import Field + from crewai.events.types.a2a_events import ( A2AAgentCardFetchedEvent, A2AArtifactReceivedEvent, @@ -102,7 +106,7 @@ from crewai.events.types.tool_usage_events import ( ) -EventTypes = ( +EventTypes = Annotated[ A2AAgentCardFetchedEvent | A2AArtifactReceivedEvent | A2AAuthenticationFailedEvent @@ -180,5 +184,6 @@ EventTypes = ( | MCPConnectionFailedEvent | MCPToolExecutionStartedEvent | MCPToolExecutionCompletedEvent - | MCPToolExecutionFailedEvent -) + | MCPToolExecutionFailedEvent, + Field(discriminator="type"), +] diff --git a/lib/crewai/src/crewai/events/types/a2a_events.py b/lib/crewai/src/crewai/events/types/a2a_events.py index d69878aac..8492c17a1 100644 --- a/lib/crewai/src/crewai/events/types/a2a_events.py +++ b/lib/crewai/src/crewai/events/types/a2a_events.py @@ -73,7 +73,7 @@ class A2ADelegationStartedEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_delegation_started" + type: Literal["a2a_delegation_started"] = "a2a_delegation_started" endpoint: str task_description: str agent_id: str @@ -106,7 +106,7 @@ class A2ADelegationCompletedEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_delegation_completed" + type: Literal["a2a_delegation_completed"] = "a2a_delegation_completed" status: str result: str | None = None error: str | None = None @@ -140,7 +140,7 @@ class A2AConversationStartedEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_conversation_started" + type: Literal["a2a_conversation_started"] = "a2a_conversation_started" agent_id: str endpoint: str context_id: str | None = None @@ -171,7 +171,7 @@ class A2AMessageSentEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_message_sent" + type: Literal["a2a_message_sent"] = "a2a_message_sent" message: str turn_number: int context_id: str | None = None @@ -203,7 +203,7 @@ class A2AResponseReceivedEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_response_received" + type: Literal["a2a_response_received"] = "a2a_response_received" response: str turn_number: int context_id: str | None = None @@ -237,7 +237,7 @@ class A2AConversationCompletedEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_conversation_completed" + type: Literal["a2a_conversation_completed"] = "a2a_conversation_completed" status: Literal["completed", "failed"] final_result: str | None = None error: str | None = None @@ -263,7 +263,7 @@ class A2APollingStartedEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_polling_started" + type: Literal["a2a_polling_started"] = "a2a_polling_started" task_id: str context_id: str | None = None polling_interval: float @@ -286,7 +286,7 @@ class A2APollingStatusEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_polling_status" + type: Literal["a2a_polling_status"] = "a2a_polling_status" task_id: str context_id: str | None = None state: str @@ -309,7 +309,7 @@ class A2APushNotificationRegisteredEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_push_notification_registered" + type: Literal["a2a_push_notification_registered"] = "a2a_push_notification_registered" task_id: str context_id: str | None = None callback_url: str @@ -334,7 +334,7 @@ class A2APushNotificationReceivedEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_push_notification_received" + type: Literal["a2a_push_notification_received"] = "a2a_push_notification_received" task_id: str context_id: str | None = None state: str @@ -359,7 +359,7 @@ class A2APushNotificationSentEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_push_notification_sent" + type: Literal["a2a_push_notification_sent"] = "a2a_push_notification_sent" task_id: str context_id: str | None = None callback_url: str @@ -381,7 +381,7 @@ class A2APushNotificationTimeoutEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_push_notification_timeout" + type: Literal["a2a_push_notification_timeout"] = "a2a_push_notification_timeout" task_id: str context_id: str | None = None timeout_seconds: float @@ -405,7 +405,7 @@ class A2AStreamingStartedEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_streaming_started" + type: Literal["a2a_streaming_started"] = "a2a_streaming_started" task_id: str | None = None context_id: str | None = None endpoint: str @@ -434,7 +434,7 @@ class A2AStreamingChunkEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_streaming_chunk" + type: Literal["a2a_streaming_chunk"] = "a2a_streaming_chunk" task_id: str | None = None context_id: str | None = None chunk: str @@ -462,7 +462,7 @@ class A2AAgentCardFetchedEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_agent_card_fetched" + type: Literal["a2a_agent_card_fetched"] = "a2a_agent_card_fetched" endpoint: str a2a_agent_name: str | None = None agent_card: dict[str, Any] | None = None @@ -486,7 +486,7 @@ class A2AAuthenticationFailedEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_authentication_failed" + type: Literal["a2a_authentication_failed"] = "a2a_authentication_failed" endpoint: str auth_type: str | None = None error: str @@ -517,7 +517,7 @@ class A2AArtifactReceivedEvent(A2AEventBase): extensions: List of A2A extension URIs in use. """ - type: str = "a2a_artifact_received" + type: Literal["a2a_artifact_received"] = "a2a_artifact_received" task_id: str artifact_id: str artifact_name: str | None = None @@ -550,7 +550,7 @@ class A2AConnectionErrorEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_connection_error" + type: Literal["a2a_connection_error"] = "a2a_connection_error" endpoint: str error: str error_type: str | None = None @@ -571,7 +571,7 @@ class A2AServerTaskStartedEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_server_task_started" + type: Literal["a2a_server_task_started"] = "a2a_server_task_started" task_id: str context_id: str metadata: dict[str, Any] | None = None @@ -587,7 +587,7 @@ class A2AServerTaskCompletedEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_server_task_completed" + type: Literal["a2a_server_task_completed"] = "a2a_server_task_completed" task_id: str context_id: str result: str @@ -603,7 +603,7 @@ class A2AServerTaskCanceledEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_server_task_canceled" + type: Literal["a2a_server_task_canceled"] = "a2a_server_task_canceled" task_id: str context_id: str metadata: dict[str, Any] | None = None @@ -619,7 +619,7 @@ class A2AServerTaskFailedEvent(A2AEventBase): metadata: Custom A2A metadata key-value pairs. """ - type: str = "a2a_server_task_failed" + type: Literal["a2a_server_task_failed"] = "a2a_server_task_failed" task_id: str context_id: str error: str @@ -634,7 +634,7 @@ class A2AParallelDelegationStartedEvent(A2AEventBase): task_description: Description of the task being delegated. """ - type: str = "a2a_parallel_delegation_started" + type: Literal["a2a_parallel_delegation_started"] = "a2a_parallel_delegation_started" endpoints: list[str] task_description: str @@ -649,7 +649,7 @@ class A2AParallelDelegationCompletedEvent(A2AEventBase): results: Summary of results from each agent. """ - type: str = "a2a_parallel_delegation_completed" + type: Literal["a2a_parallel_delegation_completed"] = "a2a_parallel_delegation_completed" endpoints: list[str] success_count: int failure_count: int diff --git a/lib/crewai/src/crewai/events/types/agent_events.py b/lib/crewai/src/crewai/events/types/agent_events.py index 5a5ab52a7..2c0a72208 100644 --- a/lib/crewai/src/crewai/events/types/agent_events.py +++ b/lib/crewai/src/crewai/events/types/agent_events.py @@ -2,8 +2,7 @@ from __future__ import annotations -from collections.abc import Sequence -from typing import Any +from typing import Any, Literal from pydantic import ConfigDict, model_validator @@ -18,9 +17,9 @@ class AgentExecutionStartedEvent(BaseEvent): agent: BaseAgent task: Any - tools: Sequence[BaseTool | CrewStructuredTool] | None + tools: list[BaseTool | CrewStructuredTool] | None task_prompt: str - type: str = "agent_execution_started" + type: Literal["agent_execution_started"] = "agent_execution_started" model_config = ConfigDict(arbitrary_types_allowed=True) @@ -44,7 +43,7 @@ class AgentExecutionCompletedEvent(BaseEvent): agent: BaseAgent task: Any output: str - type: str = "agent_execution_completed" + type: Literal["agent_execution_completed"] = "agent_execution_completed" model_config = ConfigDict(arbitrary_types_allowed=True) @@ -68,7 +67,7 @@ class AgentExecutionErrorEvent(BaseEvent): agent: BaseAgent task: Any error: str - type: str = "agent_execution_error" + type: Literal["agent_execution_error"] = "agent_execution_error" model_config = ConfigDict(arbitrary_types_allowed=True) @@ -91,9 +90,9 @@ class LiteAgentExecutionStartedEvent(BaseEvent): """Event emitted when a LiteAgent starts executing""" agent_info: dict[str, Any] - tools: Sequence[BaseTool | CrewStructuredTool] | None + tools: list[BaseTool | CrewStructuredTool] | None messages: str | list[dict[str, str]] - type: str = "lite_agent_execution_started" + type: Literal["lite_agent_execution_started"] = "lite_agent_execution_started" model_config = ConfigDict(arbitrary_types_allowed=True) @@ -103,7 +102,7 @@ class LiteAgentExecutionCompletedEvent(BaseEvent): agent_info: dict[str, Any] output: str - type: str = "lite_agent_execution_completed" + type: Literal["lite_agent_execution_completed"] = "lite_agent_execution_completed" class LiteAgentExecutionErrorEvent(BaseEvent): @@ -111,7 +110,7 @@ class LiteAgentExecutionErrorEvent(BaseEvent): agent_info: dict[str, Any] error: str - type: str = "lite_agent_execution_error" + type: Literal["lite_agent_execution_error"] = "lite_agent_execution_error" # Agent Eval events @@ -120,7 +119,7 @@ class AgentEvaluationStartedEvent(BaseEvent): agent_role: str task_id: str | None = None iteration: int - type: str = "agent_evaluation_started" + type: Literal["agent_evaluation_started"] = "agent_evaluation_started" class AgentEvaluationCompletedEvent(BaseEvent): @@ -130,7 +129,7 @@ class AgentEvaluationCompletedEvent(BaseEvent): iteration: int metric_category: Any score: Any - type: str = "agent_evaluation_completed" + type: Literal["agent_evaluation_completed"] = "agent_evaluation_completed" class AgentEvaluationFailedEvent(BaseEvent): @@ -139,4 +138,4 @@ class AgentEvaluationFailedEvent(BaseEvent): task_id: str | None = None iteration: int error: str - type: str = "agent_evaluation_failed" + type: Literal["agent_evaluation_failed"] = "agent_evaluation_failed" diff --git a/lib/crewai/src/crewai/events/types/crew_events.py b/lib/crewai/src/crewai/events/types/crew_events.py index 8fdcbfd2b..705624a0e 100644 --- a/lib/crewai/src/crewai/events/types/crew_events.py +++ b/lib/crewai/src/crewai/events/types/crew_events.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Literal from crewai.events.base_events import BaseEvent @@ -40,14 +40,14 @@ class CrewKickoffStartedEvent(CrewBaseEvent): """Event emitted when a crew starts execution""" inputs: dict[str, Any] | None - type: str = "crew_kickoff_started" + type: Literal["crew_kickoff_started"] = "crew_kickoff_started" class CrewKickoffCompletedEvent(CrewBaseEvent): """Event emitted when a crew completes execution""" output: Any - type: str = "crew_kickoff_completed" + type: Literal["crew_kickoff_completed"] = "crew_kickoff_completed" total_tokens: int = 0 @@ -55,7 +55,7 @@ class CrewKickoffFailedEvent(CrewBaseEvent): """Event emitted when a crew fails to complete execution""" error: str - type: str = "crew_kickoff_failed" + type: Literal["crew_kickoff_failed"] = "crew_kickoff_failed" class CrewTrainStartedEvent(CrewBaseEvent): @@ -64,7 +64,7 @@ class CrewTrainStartedEvent(CrewBaseEvent): n_iterations: int filename: str inputs: dict[str, Any] | None - type: str = "crew_train_started" + type: Literal["crew_train_started"] = "crew_train_started" class CrewTrainCompletedEvent(CrewBaseEvent): @@ -72,14 +72,14 @@ class CrewTrainCompletedEvent(CrewBaseEvent): n_iterations: int filename: str - type: str = "crew_train_completed" + type: Literal["crew_train_completed"] = "crew_train_completed" class CrewTrainFailedEvent(CrewBaseEvent): """Event emitted when a crew fails to complete training""" error: str - type: str = "crew_train_failed" + type: Literal["crew_train_failed"] = "crew_train_failed" class CrewTestStartedEvent(CrewBaseEvent): @@ -88,20 +88,20 @@ class CrewTestStartedEvent(CrewBaseEvent): n_iterations: int eval_llm: str | Any | None inputs: dict[str, Any] | None - type: str = "crew_test_started" + type: Literal["crew_test_started"] = "crew_test_started" class CrewTestCompletedEvent(CrewBaseEvent): """Event emitted when a crew completes testing""" - type: str = "crew_test_completed" + type: Literal["crew_test_completed"] = "crew_test_completed" class CrewTestFailedEvent(CrewBaseEvent): """Event emitted when a crew fails to complete testing""" error: str - type: str = "crew_test_failed" + type: Literal["crew_test_failed"] = "crew_test_failed" class CrewTestResultEvent(CrewBaseEvent): @@ -110,4 +110,4 @@ class CrewTestResultEvent(CrewBaseEvent): quality: float execution_duration: float model: str - type: str = "crew_test_result" + type: Literal["crew_test_result"] = "crew_test_result" diff --git a/lib/crewai/src/crewai/events/types/flow_events.py b/lib/crewai/src/crewai/events/types/flow_events.py index 826722762..ab8609d6b 100644 --- a/lib/crewai/src/crewai/events/types/flow_events.py +++ b/lib/crewai/src/crewai/events/types/flow_events.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Literal from pydantic import BaseModel, ConfigDict @@ -17,14 +17,14 @@ class FlowStartedEvent(FlowEvent): flow_name: str inputs: dict[str, Any] | None = None - type: str = "flow_started" + type: Literal["flow_started"] = "flow_started" class FlowCreatedEvent(FlowEvent): """Event emitted when a flow is created""" flow_name: str - type: str = "flow_created" + type: Literal["flow_created"] = "flow_created" class MethodExecutionStartedEvent(FlowEvent): @@ -34,7 +34,7 @@ class MethodExecutionStartedEvent(FlowEvent): method_name: str state: dict[str, Any] | BaseModel params: dict[str, Any] | None = None - type: str = "method_execution_started" + type: Literal["method_execution_started"] = "method_execution_started" class MethodExecutionFinishedEvent(FlowEvent): @@ -44,7 +44,7 @@ class MethodExecutionFinishedEvent(FlowEvent): method_name: str result: Any = None state: dict[str, Any] | BaseModel - type: str = "method_execution_finished" + type: Literal["method_execution_finished"] = "method_execution_finished" class MethodExecutionFailedEvent(FlowEvent): @@ -53,7 +53,7 @@ class MethodExecutionFailedEvent(FlowEvent): flow_name: str method_name: str error: Exception - type: str = "method_execution_failed" + type: Literal["method_execution_failed"] = "method_execution_failed" model_config = ConfigDict(arbitrary_types_allowed=True) @@ -78,7 +78,7 @@ class MethodExecutionPausedEvent(FlowEvent): flow_id: str message: str emit: list[str] | None = None - type: str = "method_execution_paused" + type: Literal["method_execution_paused"] = "method_execution_paused" class FlowFinishedEvent(FlowEvent): @@ -86,7 +86,7 @@ class FlowFinishedEvent(FlowEvent): flow_name: str result: Any | None = None - type: str = "flow_finished" + type: Literal["flow_finished"] = "flow_finished" state: dict[str, Any] | BaseModel @@ -110,14 +110,14 @@ class FlowPausedEvent(FlowEvent): state: dict[str, Any] | BaseModel message: str emit: list[str] | None = None - type: str = "flow_paused" + type: Literal["flow_paused"] = "flow_paused" class FlowPlotEvent(FlowEvent): """Event emitted when a flow plot is created""" flow_name: str - type: str = "flow_plot" + type: Literal["flow_plot"] = "flow_plot" class HumanFeedbackRequestedEvent(FlowEvent): @@ -138,7 +138,7 @@ class HumanFeedbackRequestedEvent(FlowEvent): output: Any message: str emit: list[str] | None = None - type: str = "human_feedback_requested" + type: Literal["human_feedback_requested"] = "human_feedback_requested" class HumanFeedbackReceivedEvent(FlowEvent): @@ -157,4 +157,4 @@ class HumanFeedbackReceivedEvent(FlowEvent): method_name: str feedback: str outcome: str | None = None - type: str = "human_feedback_received" + type: Literal["human_feedback_received"] = "human_feedback_received" diff --git a/lib/crewai/src/crewai/events/types/knowledge_events.py b/lib/crewai/src/crewai/events/types/knowledge_events.py index 14a08aef2..6582b8931 100644 --- a/lib/crewai/src/crewai/events/types/knowledge_events.py +++ b/lib/crewai/src/crewai/events/types/knowledge_events.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Literal from crewai.events.base_events import BaseEvent @@ -20,14 +20,14 @@ class KnowledgeEventBase(BaseEvent): class KnowledgeRetrievalStartedEvent(KnowledgeEventBase): """Event emitted when a knowledge retrieval is started.""" - type: str = "knowledge_search_query_started" + type: Literal["knowledge_search_query_started"] = "knowledge_search_query_started" class KnowledgeRetrievalCompletedEvent(KnowledgeEventBase): """Event emitted when a knowledge retrieval is completed.""" query: str - type: str = "knowledge_search_query_completed" + type: Literal["knowledge_search_query_completed"] = "knowledge_search_query_completed" retrieved_knowledge: str @@ -35,13 +35,13 @@ class KnowledgeQueryStartedEvent(KnowledgeEventBase): """Event emitted when a knowledge query is started.""" task_prompt: str - type: str = "knowledge_query_started" + type: Literal["knowledge_query_started"] = "knowledge_query_started" class KnowledgeQueryFailedEvent(KnowledgeEventBase): """Event emitted when a knowledge query fails.""" - type: str = "knowledge_query_failed" + type: Literal["knowledge_query_failed"] = "knowledge_query_failed" error: str @@ -49,12 +49,12 @@ class KnowledgeQueryCompletedEvent(KnowledgeEventBase): """Event emitted when a knowledge query is completed.""" query: str - type: str = "knowledge_query_completed" + type: Literal["knowledge_query_completed"] = "knowledge_query_completed" class KnowledgeSearchQueryFailedEvent(KnowledgeEventBase): """Event emitted when a knowledge search query fails.""" query: str - type: str = "knowledge_search_query_failed" + type: Literal["knowledge_search_query_failed"] = "knowledge_search_query_failed" error: str diff --git a/lib/crewai/src/crewai/events/types/llm_events.py b/lib/crewai/src/crewai/events/types/llm_events.py index 161b8a2a0..9c9f3dfcc 100644 --- a/lib/crewai/src/crewai/events/types/llm_events.py +++ b/lib/crewai/src/crewai/events/types/llm_events.py @@ -1,5 +1,5 @@ from enum import Enum -from typing import Any +from typing import Any, Literal from pydantic import BaseModel @@ -42,7 +42,7 @@ class LLMCallStartedEvent(LLMEventBase): multimodal content (text, images, etc.) """ - type: str = "llm_call_started" + type: Literal["llm_call_started"] = "llm_call_started" messages: str | list[dict[str, Any]] | None = None tools: list[dict[str, Any]] | None = None callbacks: list[Any] | None = None @@ -52,7 +52,7 @@ class LLMCallStartedEvent(LLMEventBase): class LLMCallCompletedEvent(LLMEventBase): """Event emitted when a LLM call completes""" - type: str = "llm_call_completed" + type: Literal["llm_call_completed"] = "llm_call_completed" messages: str | list[dict[str, Any]] | None = None response: Any call_type: LLMCallType @@ -62,7 +62,7 @@ class LLMCallFailedEvent(LLMEventBase): """Event emitted when a LLM call fails""" error: str - type: str = "llm_call_failed" + type: Literal["llm_call_failed"] = "llm_call_failed" class FunctionCall(BaseModel): @@ -80,7 +80,7 @@ class ToolCall(BaseModel): class LLMStreamChunkEvent(LLMEventBase): """Event emitted when a streaming chunk is received""" - type: str = "llm_stream_chunk" + type: Literal["llm_stream_chunk"] = "llm_stream_chunk" chunk: str tool_call: ToolCall | None = None call_type: LLMCallType | None = None diff --git a/lib/crewai/src/crewai/events/types/llm_guardrail_events.py b/lib/crewai/src/crewai/events/types/llm_guardrail_events.py index 895ac3ad3..8aee1d201 100644 --- a/lib/crewai/src/crewai/events/types/llm_guardrail_events.py +++ b/lib/crewai/src/crewai/events/types/llm_guardrail_events.py @@ -1,6 +1,6 @@ from collections.abc import Callable from inspect import getsource -from typing import Any +from typing import Any, Literal from crewai.events.base_events import BaseEvent @@ -27,7 +27,7 @@ class LLMGuardrailStartedEvent(LLMGuardrailBaseEvent): retry_count: The number of times the guardrail has been retried """ - type: str = "llm_guardrail_started" + type: Literal["llm_guardrail_started"] = "llm_guardrail_started" guardrail: str | Callable retry_count: int @@ -53,7 +53,7 @@ class LLMGuardrailCompletedEvent(LLMGuardrailBaseEvent): retry_count: The number of times the guardrail has been retried """ - type: str = "llm_guardrail_completed" + type: Literal["llm_guardrail_completed"] = "llm_guardrail_completed" success: bool result: Any error: str | None = None @@ -68,6 +68,6 @@ class LLMGuardrailFailedEvent(LLMGuardrailBaseEvent): retry_count: The number of times the guardrail has been retried """ - type: str = "llm_guardrail_failed" + type: Literal["llm_guardrail_failed"] = "llm_guardrail_failed" error: str retry_count: int diff --git a/lib/crewai/src/crewai/events/types/logging_events.py b/lib/crewai/src/crewai/events/types/logging_events.py index 31b8bdd1e..6bd0ff3e3 100644 --- a/lib/crewai/src/crewai/events/types/logging_events.py +++ b/lib/crewai/src/crewai/events/types/logging_events.py @@ -1,6 +1,6 @@ """Agent logging events that don't reference BaseAgent to avoid circular imports.""" -from typing import Any +from typing import Any, Literal from pydantic import ConfigDict @@ -13,7 +13,7 @@ class AgentLogsStartedEvent(BaseEvent): agent_role: str task_description: str | None = None verbose: bool = False - type: str = "agent_logs_started" + type: Literal["agent_logs_started"] = "agent_logs_started" class AgentLogsExecutionEvent(BaseEvent): @@ -22,6 +22,6 @@ class AgentLogsExecutionEvent(BaseEvent): agent_role: str formatted_answer: Any verbose: bool = False - type: str = "agent_logs_execution" + type: Literal["agent_logs_execution"] = "agent_logs_execution" model_config = ConfigDict(arbitrary_types_allowed=True) diff --git a/lib/crewai/src/crewai/events/types/mcp_events.py b/lib/crewai/src/crewai/events/types/mcp_events.py index d360aa62a..30ed27b5c 100644 --- a/lib/crewai/src/crewai/events/types/mcp_events.py +++ b/lib/crewai/src/crewai/events/types/mcp_events.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Any +from typing import Any, Literal from crewai.events.base_events import BaseEvent @@ -24,7 +24,7 @@ class MCPEvent(BaseEvent): class MCPConnectionStartedEvent(MCPEvent): """Event emitted when starting to connect to an MCP server.""" - type: str = "mcp_connection_started" + type: Literal["mcp_connection_started"] = "mcp_connection_started" connect_timeout: int | None = None is_reconnect: bool = ( False # True if this is a reconnection, False for first connection @@ -34,7 +34,7 @@ class MCPConnectionStartedEvent(MCPEvent): class MCPConnectionCompletedEvent(MCPEvent): """Event emitted when successfully connected to an MCP server.""" - type: str = "mcp_connection_completed" + type: Literal["mcp_connection_completed"] = "mcp_connection_completed" started_at: datetime | None = None completed_at: datetime | None = None connection_duration_ms: float | None = None @@ -46,7 +46,7 @@ class MCPConnectionCompletedEvent(MCPEvent): class MCPConnectionFailedEvent(MCPEvent): """Event emitted when connection to an MCP server fails.""" - type: str = "mcp_connection_failed" + type: Literal["mcp_connection_failed"] = "mcp_connection_failed" error: str error_type: str | None = None # "timeout", "authentication", "network", etc. started_at: datetime | None = None @@ -56,7 +56,7 @@ class MCPConnectionFailedEvent(MCPEvent): class MCPToolExecutionStartedEvent(MCPEvent): """Event emitted when starting to execute an MCP tool.""" - type: str = "mcp_tool_execution_started" + type: Literal["mcp_tool_execution_started"] = "mcp_tool_execution_started" tool_name: str tool_args: dict[str, Any] | None = None @@ -64,7 +64,7 @@ class MCPToolExecutionStartedEvent(MCPEvent): class MCPToolExecutionCompletedEvent(MCPEvent): """Event emitted when MCP tool execution completes.""" - type: str = "mcp_tool_execution_completed" + type: Literal["mcp_tool_execution_completed"] = "mcp_tool_execution_completed" tool_name: str tool_args: dict[str, Any] | None = None result: Any | None = None @@ -76,7 +76,7 @@ class MCPToolExecutionCompletedEvent(MCPEvent): class MCPToolExecutionFailedEvent(MCPEvent): """Event emitted when MCP tool execution fails.""" - type: str = "mcp_tool_execution_failed" + type: Literal["mcp_tool_execution_failed"] = "mcp_tool_execution_failed" tool_name: str tool_args: dict[str, Any] | None = None error: str diff --git a/lib/crewai/src/crewai/events/types/memory_events.py b/lib/crewai/src/crewai/events/types/memory_events.py index 0fd57a352..1d6b05017 100644 --- a/lib/crewai/src/crewai/events/types/memory_events.py +++ b/lib/crewai/src/crewai/events/types/memory_events.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Literal from crewai.events.base_events import BaseEvent @@ -23,7 +23,7 @@ class MemoryBaseEvent(BaseEvent): class MemoryQueryStartedEvent(MemoryBaseEvent): """Event emitted when a memory query is started""" - type: str = "memory_query_started" + type: Literal["memory_query_started"] = "memory_query_started" query: str limit: int score_threshold: float | None = None @@ -32,7 +32,7 @@ class MemoryQueryStartedEvent(MemoryBaseEvent): class MemoryQueryCompletedEvent(MemoryBaseEvent): """Event emitted when a memory query is completed successfully""" - type: str = "memory_query_completed" + type: Literal["memory_query_completed"] = "memory_query_completed" query: str results: Any limit: int @@ -43,7 +43,7 @@ class MemoryQueryCompletedEvent(MemoryBaseEvent): class MemoryQueryFailedEvent(MemoryBaseEvent): """Event emitted when a memory query fails""" - type: str = "memory_query_failed" + type: Literal["memory_query_failed"] = "memory_query_failed" query: str limit: int score_threshold: float | None = None @@ -53,7 +53,7 @@ class MemoryQueryFailedEvent(MemoryBaseEvent): class MemorySaveStartedEvent(MemoryBaseEvent): """Event emitted when a memory save operation is started""" - type: str = "memory_save_started" + type: Literal["memory_save_started"] = "memory_save_started" value: str | None = None metadata: dict[str, Any] | None = None agent_role: str | None = None @@ -62,7 +62,7 @@ class MemorySaveStartedEvent(MemoryBaseEvent): class MemorySaveCompletedEvent(MemoryBaseEvent): """Event emitted when a memory save operation is completed successfully""" - type: str = "memory_save_completed" + type: Literal["memory_save_completed"] = "memory_save_completed" value: str metadata: dict[str, Any] | None = None agent_role: str | None = None @@ -72,7 +72,7 @@ class MemorySaveCompletedEvent(MemoryBaseEvent): class MemorySaveFailedEvent(MemoryBaseEvent): """Event emitted when a memory save operation fails""" - type: str = "memory_save_failed" + type: Literal["memory_save_failed"] = "memory_save_failed" value: str | None = None metadata: dict[str, Any] | None = None agent_role: str | None = None @@ -82,14 +82,14 @@ class MemorySaveFailedEvent(MemoryBaseEvent): class MemoryRetrievalStartedEvent(MemoryBaseEvent): """Event emitted when memory retrieval for a task prompt starts""" - type: str = "memory_retrieval_started" + type: Literal["memory_retrieval_started"] = "memory_retrieval_started" task_id: str | None = None class MemoryRetrievalCompletedEvent(MemoryBaseEvent): """Event emitted when memory retrieval for a task prompt completes successfully""" - type: str = "memory_retrieval_completed" + type: Literal["memory_retrieval_completed"] = "memory_retrieval_completed" task_id: str | None = None memory_content: str retrieval_time_ms: float @@ -98,6 +98,6 @@ class MemoryRetrievalCompletedEvent(MemoryBaseEvent): class MemoryRetrievalFailedEvent(MemoryBaseEvent): """Event emitted when memory retrieval for a task prompt fails.""" - type: str = "memory_retrieval_failed" + type: Literal["memory_retrieval_failed"] = "memory_retrieval_failed" task_id: str | None = None error: str diff --git a/lib/crewai/src/crewai/events/types/reasoning_events.py b/lib/crewai/src/crewai/events/types/reasoning_events.py index 53ac47b07..b9cffe99b 100644 --- a/lib/crewai/src/crewai/events/types/reasoning_events.py +++ b/lib/crewai/src/crewai/events/types/reasoning_events.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Literal from crewai.events.base_events import BaseEvent @@ -24,7 +24,7 @@ class ReasoningEvent(BaseEvent): class AgentReasoningStartedEvent(ReasoningEvent): """Event emitted when an agent starts reasoning about a task.""" - type: str = "agent_reasoning_started" + type: Literal["agent_reasoning_started"] = "agent_reasoning_started" agent_role: str task_id: str @@ -32,7 +32,7 @@ class AgentReasoningStartedEvent(ReasoningEvent): class AgentReasoningCompletedEvent(ReasoningEvent): """Event emitted when an agent finishes its reasoning process.""" - type: str = "agent_reasoning_completed" + type: Literal["agent_reasoning_completed"] = "agent_reasoning_completed" agent_role: str task_id: str plan: str @@ -42,7 +42,7 @@ class AgentReasoningCompletedEvent(ReasoningEvent): class AgentReasoningFailedEvent(ReasoningEvent): """Event emitted when the reasoning process fails.""" - type: str = "agent_reasoning_failed" + type: Literal["agent_reasoning_failed"] = "agent_reasoning_failed" agent_role: str task_id: str error: str diff --git a/lib/crewai/src/crewai/events/types/task_events.py b/lib/crewai/src/crewai/events/types/task_events.py index cd9fc1e72..9c9e82be1 100644 --- a/lib/crewai/src/crewai/events/types/task_events.py +++ b/lib/crewai/src/crewai/events/types/task_events.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Literal from crewai.events.base_events import BaseEvent from crewai.tasks.task_output import TaskOutput @@ -7,7 +7,7 @@ from crewai.tasks.task_output import TaskOutput class TaskStartedEvent(BaseEvent): """Event emitted when a task starts""" - type: str = "task_started" + type: Literal["task_started"] = "task_started" context: str | None task: Any | None = None @@ -28,7 +28,7 @@ class TaskCompletedEvent(BaseEvent): """Event emitted when a task completes""" output: TaskOutput - type: str = "task_completed" + type: Literal["task_completed"] = "task_completed" task: Any | None = None def __init__(self, **data): @@ -48,7 +48,7 @@ class TaskFailedEvent(BaseEvent): """Event emitted when a task fails""" error: str - type: str = "task_failed" + type: Literal["task_failed"] = "task_failed" task: Any | None = None def __init__(self, **data): @@ -67,7 +67,7 @@ class TaskFailedEvent(BaseEvent): class TaskEvaluationEvent(BaseEvent): """Event emitted when a task evaluation is completed""" - type: str = "task_evaluation" + type: Literal["task_evaluation"] = "task_evaluation" evaluation_type: str task: Any | None = None diff --git a/lib/crewai/src/crewai/events/types/tool_usage_events.py b/lib/crewai/src/crewai/events/types/tool_usage_events.py index 7fe9b897f..396af77af 100644 --- a/lib/crewai/src/crewai/events/types/tool_usage_events.py +++ b/lib/crewai/src/crewai/events/types/tool_usage_events.py @@ -1,6 +1,6 @@ from collections.abc import Callable from datetime import datetime -from typing import Any +from typing import Any, Literal from pydantic import ConfigDict @@ -55,7 +55,7 @@ class ToolUsageEvent(BaseEvent): class ToolUsageStartedEvent(ToolUsageEvent): """Event emitted when a tool execution is started""" - type: str = "tool_usage_started" + type: Literal["tool_usage_started"] = "tool_usage_started" class ToolUsageFinishedEvent(ToolUsageEvent): @@ -65,35 +65,35 @@ class ToolUsageFinishedEvent(ToolUsageEvent): finished_at: datetime from_cache: bool = False output: Any - type: str = "tool_usage_finished" + type: Literal["tool_usage_finished"] = "tool_usage_finished" class ToolUsageErrorEvent(ToolUsageEvent): """Event emitted when a tool execution encounters an error""" error: Any - type: str = "tool_usage_error" + type: Literal["tool_usage_error"] = "tool_usage_error" class ToolValidateInputErrorEvent(ToolUsageEvent): """Event emitted when a tool input validation encounters an error""" error: Any - type: str = "tool_validate_input_error" + type: Literal["tool_validate_input_error"] = "tool_validate_input_error" class ToolSelectionErrorEvent(ToolUsageEvent): """Event emitted when a tool selection encounters an error""" error: Any - type: str = "tool_selection_error" + type: Literal["tool_selection_error"] = "tool_selection_error" class ToolExecutionErrorEvent(BaseEvent): """Event emitted when a tool execution encounters an error""" error: Any - type: str = "tool_execution_error" + type: Literal["tool_execution_error"] = "tool_execution_error" tool_name: str tool_args: dict[str, Any] tool_class: Callable diff --git a/lib/crewai/src/crewai/flow/flow.py b/lib/crewai/src/crewai/flow/flow.py index b92d10d2d..2b5a13822 100644 --- a/lib/crewai/src/crewai/flow/flow.py +++ b/lib/crewai/src/crewai/flow/flow.py @@ -7,7 +7,7 @@ for building event-driven workflows with conditional execution and routing. from __future__ import annotations import asyncio -from collections.abc import Callable, Sequence +from collections.abc import Callable from concurrent.futures import Future import copy import inspect @@ -2382,7 +2382,7 @@ class Flow(Generic[T], metaclass=FlowMeta): message: str, output: Any, metadata: dict[str, Any] | None = None, - emit: Sequence[str] | None = None, + emit: list[str] | None = None, ) -> str: """Request feedback from a human. Args: diff --git a/lib/crewai/src/crewai/flow/human_feedback.py b/lib/crewai/src/crewai/flow/human_feedback.py index 568aaf060..68122c0f9 100644 --- a/lib/crewai/src/crewai/flow/human_feedback.py +++ b/lib/crewai/src/crewai/flow/human_feedback.py @@ -53,7 +53,7 @@ Example (asynchronous with custom provider): from __future__ import annotations import asyncio -from collections.abc import Callable, Sequence +from collections.abc import Callable from dataclasses import dataclass, field from datetime import datetime from functools import wraps @@ -128,7 +128,7 @@ class HumanFeedbackConfig: """ message: str - emit: Sequence[str] | None = None + emit: list[str] | None = None llm: str | BaseLLM | None = None default_outcome: str | None = None metadata: dict[str, Any] | None = None @@ -154,7 +154,7 @@ class HumanFeedbackMethod(FlowMethod[Any, Any]): def human_feedback( message: str, - emit: Sequence[str] | None = None, + emit: list[str] | None = None, llm: str | BaseLLM | None = None, default_outcome: str | None = None, metadata: dict[str, Any] | None = None, diff --git a/lib/crewai/src/crewai/llms/base_llm.py b/lib/crewai/src/crewai/llms/base_llm.py index 2a6def197..93f99fa44 100644 --- a/lib/crewai/src/crewai/llms/base_llm.py +++ b/lib/crewai/src/crewai/llms/base_llm.py @@ -404,7 +404,7 @@ class BaseLLM(ABC): from_agent: Agent | None = None, tool_call: dict[str, Any] | None = None, call_type: LLMCallType | None = None, - response_id: str | None = None + response_id: str | None = None, ) -> None: """Emit stream chunk event. @@ -427,7 +427,7 @@ class BaseLLM(ABC): from_task=from_task, from_agent=from_agent, call_type=call_type, - response_id=response_id + response_id=response_id, ), ) @@ -620,13 +620,11 @@ class BaseLLM(ABC): try: # Try to parse as JSON first if response.strip().startswith("{") or response.strip().startswith("["): - data = json.loads(response) - return response_format.model_validate(data) + return response_format.model_validate_json(response) json_match = _JSON_EXTRACTION_PATTERN.search(response) if json_match: - data = json.loads(json_match.group()) - return response_format.model_validate(data) + return response_format.model_validate_json(json_match.group()) raise ValueError("No JSON found in response") diff --git a/lib/crewai/src/crewai/llms/providers/bedrock/completion.py b/lib/crewai/src/crewai/llms/providers/bedrock/completion.py index 850835ff1..1d4c660d2 100644 --- a/lib/crewai/src/crewai/llms/providers/bedrock/completion.py +++ b/lib/crewai/src/crewai/llms/providers/bedrock/completion.py @@ -1,6 +1,6 @@ from __future__ import annotations -from collections.abc import Mapping, Sequence +from collections.abc import Sequence from contextlib import AsyncExitStack import json import logging @@ -538,7 +538,7 @@ class BedrockCompletion(BaseLLM): self, messages: list[LLMMessage], body: BedrockConverseRequestBody, - available_functions: Mapping[str, Any] | None = None, + available_functions: dict[str, Any] | None = None, from_task: Any | None = None, from_agent: Any | None = None, response_model: type[BaseModel] | None = None, @@ -1009,7 +1009,7 @@ class BedrockCompletion(BaseLLM): self, messages: list[LLMMessage], body: BedrockConverseRequestBody, - available_functions: Mapping[str, Any] | None = None, + available_functions: dict[str, Any] | None = None, from_task: Any | None = None, from_agent: Any | None = None, response_model: type[BaseModel] | None = None, diff --git a/lib/crewai/src/crewai/rag/chromadb/types.py b/lib/crewai/src/crewai/rag/chromadb/types.py index 982b2fbe1..3e63c2e57 100644 --- a/lib/crewai/src/crewai/rag/chromadb/types.py +++ b/lib/crewai/src/crewai/rag/chromadb/types.py @@ -1,6 +1,5 @@ """Type definitions specific to ChromaDB implementation.""" -from collections.abc import Mapping from typing import Any, NamedTuple from chromadb.api import AsyncClientAPI, ClientAPI @@ -49,7 +48,7 @@ class PreparedDocuments(NamedTuple): ids: list[str] texts: list[str] - metadatas: list[Mapping[str, str | int | float | bool]] + metadatas: list[dict[str, str | int | float | bool]] class ExtractedSearchParams(NamedTuple): diff --git a/lib/crewai/src/crewai/rag/chromadb/utils.py b/lib/crewai/src/crewai/rag/chromadb/utils.py index 4f17bef5a..e8166b1bc 100644 --- a/lib/crewai/src/crewai/rag/chromadb/utils.py +++ b/lib/crewai/src/crewai/rag/chromadb/utils.py @@ -1,6 +1,5 @@ """Utility functions for ChromaDB client implementation.""" -from collections.abc import Mapping import hashlib import json from typing import Literal, TypeGuard, cast @@ -66,7 +65,7 @@ def _prepare_documents_for_chromadb( """ ids: list[str] = [] texts: list[str] = [] - metadatas: list[Mapping[str, str | int | float | bool]] = [] + metadatas: list[dict[str, str | int | float | bool]] = [] seen_ids: dict[str, int] = {} try: @@ -111,7 +110,7 @@ def _prepare_documents_for_chromadb( def _create_batch_slice( prepared: PreparedDocuments, start_index: int, batch_size: int -) -> tuple[list[str], list[str], list[Mapping[str, str | int | float | bool]] | None]: +) -> tuple[list[str], list[str], list[dict[str, str | int | float | bool]] | None]: """Create a batch slice from prepared documents. Args: diff --git a/lib/crewai/src/crewai/rag/embeddings/types.py b/lib/crewai/src/crewai/rag/embeddings/types.py index 794f4c6f9..7885ae208 100644 --- a/lib/crewai/src/crewai/rag/embeddings/types.py +++ b/lib/crewai/src/crewai/rag/embeddings/types.py @@ -1,6 +1,8 @@ """Type definitions for the embeddings module.""" -from typing import Any, Literal, TypeAlias +from typing import Annotated, Any, Literal, TypeAlias + +from pydantic import Field from crewai.rag.core.base_embeddings_provider import BaseEmbeddingsProvider from crewai.rag.embeddings.providers.aws.types import BedrockProviderSpec @@ -29,7 +31,7 @@ from crewai.rag.embeddings.providers.text2vec.types import Text2VecProviderSpec from crewai.rag.embeddings.providers.voyageai.types import VoyageAIProviderSpec -ProviderSpec: TypeAlias = ( +ProviderSpec: TypeAlias = Annotated[ AzureProviderSpec | BedrockProviderSpec | CohereProviderSpec @@ -47,8 +49,9 @@ ProviderSpec: TypeAlias = ( | Text2VecProviderSpec | VertexAIProviderSpec | VoyageAIProviderSpec - | WatsonXProviderSpec -) + | WatsonXProviderSpec, + Field(discriminator="provider"), +] AllowedEmbeddingProviders = Literal[ "azure", diff --git a/lib/crewai/src/crewai/rag/types.py b/lib/crewai/src/crewai/rag/types.py index fa154c0c2..cbf4bd677 100644 --- a/lib/crewai/src/crewai/rag/types.py +++ b/lib/crewai/src/crewai/rag/types.py @@ -1,6 +1,6 @@ """Type definitions for RAG (Retrieval-Augmented Generation) systems.""" -from collections.abc import Callable, Mapping +from collections.abc import Callable from typing import Any, TypeAlias from typing_extensions import Required, TypedDict @@ -19,8 +19,8 @@ class BaseRecord(TypedDict, total=False): doc_id: str content: Required[str] metadata: ( - Mapping[str, str | int | float | bool] - | list[Mapping[str, str | int | float | bool]] + dict[str, str | int | float | bool] + | list[dict[str, str | int | float | bool]] ) diff --git a/lib/crewai/src/crewai/tools/structured_tool.py b/lib/crewai/src/crewai/tools/structured_tool.py index 44f0af2d9..b9cf682f7 100644 --- a/lib/crewai/src/crewai/tools/structured_tool.py +++ b/lib/crewai/src/crewai/tools/structured_tool.py @@ -200,9 +200,12 @@ class CrewStructuredTool: """ if isinstance(raw_args, str): try: - raw_args = json.loads(raw_args) + validated_args = self.args_schema.model_validate_json(raw_args) + return validated_args.model_dump() except json.JSONDecodeError as e: raise ValueError(f"Failed to parse arguments as JSON: {e}") from e + except Exception as e: + raise ValueError(f"Arguments validation failed: {e}") from e try: validated_args = self.args_schema.model_validate(raw_args) diff --git a/lib/crewai/src/crewai/utilities/agent_utils.py b/lib/crewai/src/crewai/utilities/agent_utils.py index af4f464d9..2244099a5 100644 --- a/lib/crewai/src/crewai/utilities/agent_utils.py +++ b/lib/crewai/src/crewai/utilities/agent_utils.py @@ -1,7 +1,7 @@ from __future__ import annotations import asyncio -from collections.abc import Callable, Sequence +from collections.abc import Callable import json import re from typing import TYPE_CHECKING, Any, Final, Literal, TypedDict @@ -98,7 +98,7 @@ def parse_tools(tools: list[BaseTool]) -> list[CrewStructuredTool]: return tools_list -def get_tool_names(tools: Sequence[CrewStructuredTool | BaseTool]) -> str: +def get_tool_names(tools: list[CrewStructuredTool | BaseTool]) -> str: """Get the sanitized names of the tools. Args: @@ -111,7 +111,7 @@ def get_tool_names(tools: Sequence[CrewStructuredTool | BaseTool]) -> str: def render_text_description_and_args( - tools: Sequence[CrewStructuredTool | BaseTool], + tools: list[CrewStructuredTool | BaseTool], ) -> str: """Render the tool name, description, and args in plain text. @@ -130,7 +130,7 @@ def render_text_description_and_args( def convert_tools_to_openai_schema( - tools: Sequence[BaseTool | CrewStructuredTool], + tools: list[BaseTool | CrewStructuredTool], ) -> tuple[list[dict[str, Any]], dict[str, Callable[..., Any]]]: """Convert CrewAI tools to OpenAI function calling format.