From 9bf0a19da7b55e7161e6478c8599fc1c313fb54e Mon Sep 17 00:00:00 2001 From: Steven Hartland Date: Wed, 4 Jun 2025 08:18:38 +0100 Subject: [PATCH] chore(python-sdk): modernise type hints Leverage __future__ import annotations to enable support for streamlined type hints using | vs Union from PEP 604. Future annotations was enabled across the codebase so that any additional use of Optional or Union would be flagged by type linters. Removed unused imports, guarded import under TYPE_CHECKING where necessary. Fixed accept parameter definition for EventEncoder and added a missing comment. Fixes: #50 --- docs/sdk/python/core/events.mdx | 68 +++++++------- docs/sdk/python/core/types.mdx | 18 ++-- python-sdk/ag_ui/__init__.py | 3 + python-sdk/ag_ui/core/__init__.py | 2 + python-sdk/ag_ui/core/events.py | 94 +++++++++---------- python-sdk/ag_ui/core/types.py | 17 ++-- python-sdk/ag_ui/encoder/__init__.py | 2 + python-sdk/ag_ui/encoder/encoder.py | 15 ++- python-sdk/tests/test_encoder.py | 2 + python-sdk/tests/test_events.py | 7 +- python-sdk/tests/test_types.py | 2 + .../crewai/python/ag_ui_crewai/endpoint.py | 6 +- .../examples/predictive_state_updates.py | 5 +- .../ag_ui_crewai/examples/shared_state.py | 8 +- .../crewai/python/ag_ui_crewai/sdk.py | 8 +- .../examples/agents/agentic_chat/agent.py | 5 +- .../agents/agentic_generative_ui/agent.py | 5 +- .../agents/human_in_the_loop/agent.py | 3 +- .../agents/predictive_state_updates/agent.py | 7 +- .../examples/agents/shared_state/agent.py | 6 +- .../agents/tool_based_generative_ui/agent.py | 4 +- .../langgraph/python/ag_ui_langgraph/agent.py | 49 +++++----- .../python/ag_ui_langgraph/endpoint.py | 4 +- .../examples/agents/agentic_chat.py | 5 +- .../examples/agents/agentic_generative_ui.py | 5 +- .../agents/predictive_state_updates.py | 7 +- .../examples/agents/shared_state.py | 6 +- .../agents/tool_based_generative_ui.py | 4 +- .../langgraph/python/ag_ui_langgraph/types.py | 34 ++++--- .../langgraph/python/ag_ui_langgraph/utils.py | 6 +- .../server-py/server/routers/shared_state.py | 4 +- .../python/example_server/agentic_chat.py | 2 +- 32 files changed, 234 insertions(+), 179 deletions(-) create mode 100644 python-sdk/ag_ui/__init__.py diff --git a/docs/sdk/python/core/events.mdx b/docs/sdk/python/core/events.mdx index 6d5cdc93..034c7797 100644 --- a/docs/sdk/python/core/events.mdx +++ b/docs/sdk/python/core/events.mdx @@ -48,15 +48,15 @@ shared across all event types. ```python class BaseEvent(ConfiguredBaseModel): type: EventType - timestamp: Optional[int] = None - raw_event: Optional[Any] = None + timestamp: int | None = None + raw_event: Any = None ``` | Property | Type | Description | | ----------- | --------------- | ----------------------------------------------------- | | `type` | `EventType` | The type of event (discriminator field for the union) | -| `timestamp` | `Optional[int]` | Timestamp when the event was created | -| `raw_event` | `Optional[Any]` | Original event data if this event was transformed | +| `timestamp` | `int | None` | Timestamp when the event was created | +| `raw_event` | `Any` | Original event data if this event was transformed | ## Lifecycle Events @@ -91,14 +91,14 @@ class RunFinishedEvent(BaseEvent): type: Literal[EventType.RUN_FINISHED] thread_id: str run_id: str - result: Optional[Any] = None + result: Any = None ``` | Property | Type | Description | | ----------- | --------------- | ------------------------------ | | `thread_id` | `str` | ID of the conversation thread | | `run_id` | `str` | ID of the agent run | -| `result` | `Optional[Any]` | Result data from the agent run | +| `result` | `Any` | Result data from the agent run | ### RunErrorEvent @@ -110,13 +110,13 @@ Signals an error during an agent run. class RunErrorEvent(BaseEvent): type: Literal[EventType.RUN_ERROR] message: str - code: Optional[str] = None + code: str | None = None ``` | Property | Type | Description | | --------- | --------------- | ------------- | | `message` | `str` | Error message | -| `code` | `Optional[str]` | Error code | +| `code` | `str | None` | Error code | ### StepStartedEvent @@ -225,14 +225,14 @@ class ToolCallStartEvent(BaseEvent): type: Literal[EventType.TOOL_CALL_START] tool_call_id: str tool_call_name: str - parent_message_id: Optional[str] = None + parent_message_id: str | None = None ``` | Property | Type | Description | | ------------------- | --------------- | ----------------------------------- | | `tool_call_id` | `str` | Unique identifier for the tool call | | `tool_call_name` | `str` | Name of the tool being called | -| `parent_message_id` | `Optional[str]` | ID of the parent message | +| `parent_message_id` | `str | None` | ID of the parent message | ### ToolCallArgsEvent @@ -280,7 +280,7 @@ class ToolCallResultEvent(BaseEvent): type: Literal[EventType.TOOL_CALL_RESULT] tool_call_id: str content: str - role: Optional[Literal["tool"]] = None + role: Literal["tool"] | None = None ``` | Property | Type | Description | @@ -288,7 +288,7 @@ class ToolCallResultEvent(BaseEvent): | `message_id` | `str` | ID of the conversation message this result belongs to | | `tool_call_id` | `str` | Matches the ID from the corresponding ToolCallStartEvent | | `content` | `str` | The actual result/output content from the tool execution | -| `role` | `Optional[Literal["tool"]]` | Optional role identifier, typically "tool" for tool results | +| `role` | `Literal["tool"] | None` | Optional role identifier, typically "tool" for tool results | ## State Management Events @@ -354,13 +354,13 @@ Used to pass through events from external systems. class RawEvent(BaseEvent): type: Literal[EventType.RAW] event: Any - source: Optional[str] = None + source: str | None = None ``` | Property | Type | Description | | -------- | --------------- | ------------------- | | `event` | `Any` | Original event data | -| `source` | `Optional[str]` | Source of the event | +| `source` | `str | None` | Source of the event | ### CustomEvent @@ -388,25 +388,27 @@ The SDK uses Pydantic's discriminated unions for event validation: ```python Event = Annotated[ - Union[ - TextMessageStartEvent, - TextMessageContentEvent, - TextMessageEndEvent, - ToolCallStartEvent, - ToolCallArgsEvent, - ToolCallEndEvent, - ToolCallResultEvent, - StateSnapshotEvent, - StateDeltaEvent, - MessagesSnapshotEvent, - RawEvent, - CustomEvent, - RunStartedEvent, - RunFinishedEvent, - RunErrorEvent, - StepStartedEvent, - StepFinishedEvent, - ], + TextMessageStartEvent | + TextMessageContentEvent | + TextMessageEndEvent | + TextMessageChunkEvent | + ToolCallStartEvent | + ToolCallArgsEvent | + ToolCallEndEvent | + ToolCallChunkEvent | + ToolCallResultEvent | + ThinkingStartEvent | + ThinkingEndEvent | + StateSnapshotEvent | + StateDeltaEvent | + MessagesSnapshotEvent | + RawEvent | + CustomEvent | + RunStartedEvent | + RunFinishedEvent | + RunErrorEvent | + StepStartedEvent | + StepFinishedEvent, Field(discriminator="type") ] ``` diff --git a/docs/sdk/python/core/types.mdx b/docs/sdk/python/core/types.mdx index 836570b6..6a2fbfd8 100644 --- a/docs/sdk/python/core/types.mdx +++ b/docs/sdk/python/core/types.mdx @@ -71,7 +71,7 @@ class DeveloperMessage(BaseMessage): | `id` | `str` | Unique identifier for the message | | `role` | `Literal["developer"]` | Role of the message sender, fixed as "developer" | | `content` | `str` | Text content of the message (required) | -| `name` | `Optional[str]` | Optional name of the sender | +| `name` | `str | None` | Optional name of the sender | ### SystemMessage @@ -90,7 +90,7 @@ class SystemMessage(BaseMessage): | `id` | `str` | Unique identifier for the message | | `role` | `Literal["system"]` | Role of the message sender, fixed as "system" | | `content` | `str` | Text content of the message (required) | -| `name` | `Optional[str]` | Optional name of the sender | +| `name` | `str | None` | Optional name of the sender | ### AssistantMessage @@ -101,17 +101,17 @@ Represents a message from an assistant. ```python class AssistantMessage(BaseMessage): role: Literal["assistant"] - content: Optional[str] = None - tool_calls: Optional[List[ToolCall]] = None + content: str | None = None + tool_calls: List[ToolCall] | None = None ``` | Property | Type | Description | | ------------ | -------------------------- | ------------------------------------------------ | | `id` | `str` | Unique identifier for the message | | `role` | `Literal["assistant"]` | Role of the message sender, fixed as "assistant" | -| `content` | `Optional[str]` | Text content of the message | -| `name` | `Optional[str]` | Name of the sender | -| `tool_calls` | `Optional[List[ToolCall]]` | Tool calls made in this message | +| `content` | `str | None`. | Text content of the message | +| `name` | `str | None` | Name of the sender | +| `tool_calls` | `List[ToolCall] | None` | Tool calls made in this message | ### UserMessage @@ -130,7 +130,7 @@ class UserMessage(BaseMessage): | `id` | `str` | Unique identifier for the message | | `role` | `Literal["user"]` | Role of the message sender, fixed as "user" | | `content` | `str` | Text content of the message (required) | -| `name` | `Optional[str]` | Optional name of the sender | +| `name` | `str | None` | Optional name of the sender | ### ToolMessage @@ -161,7 +161,7 @@ A union type representing any type of message in the system. ```python Message = Annotated[ - Union[DeveloperMessage, SystemMessage, AssistantMessage, UserMessage, ToolMessage], + DeveloperMessage | SystemMessage | AssistantMessage | UserMessage | ToolMessage, Field(discriminator="role") ] ``` diff --git a/python-sdk/ag_ui/__init__.py b/python-sdk/ag_ui/__init__.py new file mode 100644 index 00000000..fdf72ee0 --- /dev/null +++ b/python-sdk/ag_ui/__init__.py @@ -0,0 +1,3 @@ +""" +Agent User Interaction Protocol Python SDK +""" diff --git a/python-sdk/ag_ui/core/__init__.py b/python-sdk/ag_ui/core/__init__.py index 7e909ad5..33985d39 100644 --- a/python-sdk/ag_ui/core/__init__.py +++ b/python-sdk/ag_ui/core/__init__.py @@ -2,6 +2,8 @@ This module contains the core types and events for the Agent User Interaction Protocol. """ +from __future__ import annotations + from ag_ui.core.events import ( EventType, BaseEvent, diff --git a/python-sdk/ag_ui/core/events.py b/python-sdk/ag_ui/core/events.py index af1415d7..c1ee3707 100644 --- a/python-sdk/ag_ui/core/events.py +++ b/python-sdk/ag_ui/core/events.py @@ -2,8 +2,10 @@ This module contains the event types for the Agent User Interaction Protocol Python SDK. """ +from __future__ import annotations + from enum import Enum -from typing import Annotated, Any, List, Literal, Optional, Union +from typing import Annotated, Any, List, Literal from pydantic import Field @@ -45,8 +47,8 @@ class BaseEvent(ConfiguredBaseModel): Base event for all events in the Agent User Interaction Protocol. """ type: EventType - timestamp: Optional[int] = None - raw_event: Optional[Any] = None + timestamp: int | None = None + raw_event: Any = None class TextMessageStartEvent(BaseEvent): @@ -79,32 +81,28 @@ class TextMessageChunkEvent(BaseEvent): Event containing a chunk of text message content. """ type: Literal[EventType.TEXT_MESSAGE_CHUNK] = EventType.TEXT_MESSAGE_CHUNK # pyright: ignore[reportIncompatibleVariableOverride] - message_id: Optional[str] = None - role: Optional[Literal["assistant"]] = None - delta: Optional[str] = None + message_id: str | None = None + role: Literal["assistant"] | None = None + delta: str | None = None class ThinkingTextMessageStartEvent(BaseEvent): """ Event indicating the start of a thinking text message. """ - type: Literal[EventType.THINKING_TEXT_MESSAGE_START] + type: Literal[EventType.THINKING_TEXT_MESSAGE_START] = EventType.THINKING_TEXT_MESSAGE_START # pyright: ignore[reportIncompatibleVariableOverride] class ThinkingTextMessageContentEvent(BaseEvent): """ Event indicating a piece of a thinking text message. """ - type: Literal[EventType.THINKING_TEXT_MESSAGE_CONTENT] - delta: str # This should not be an empty string - - def model_post_init(self, __context): - if len(self.delta) == 0: - raise ValueError("Delta must not be an empty string") + type: Literal[EventType.THINKING_TEXT_MESSAGE_CONTENT] = EventType.THINKING_TEXT_MESSAGE_CONTENT # pyright: ignore[reportIncompatibleVariableOverride] + delta: str = Field(min_length=1) class ThinkingTextMessageEndEvent(BaseEvent): """ Event indicating the end of a thinking text message. """ - type: Literal[EventType.THINKING_TEXT_MESSAGE_END] + type: Literal[EventType.THINKING_TEXT_MESSAGE_END] = EventType.THINKING_TEXT_MESSAGE_END # pyright: ignore[reportIncompatibleVariableOverride] class ToolCallStartEvent(BaseEvent): """ @@ -113,7 +111,7 @@ class ToolCallStartEvent(BaseEvent): type: Literal[EventType.TOOL_CALL_START] = EventType.TOOL_CALL_START # pyright: ignore[reportIncompatibleVariableOverride] tool_call_id: str tool_call_name: str - parent_message_id: Optional[str] = None + parent_message_id: str | None = None class ToolCallArgsEvent(BaseEvent): @@ -137,33 +135,33 @@ class ToolCallChunkEvent(BaseEvent): Event containing a chunk of tool call content. """ type: Literal[EventType.TOOL_CALL_CHUNK] = EventType.TOOL_CALL_CHUNK # pyright: ignore[reportIncompatibleVariableOverride] - tool_call_id: Optional[str] = None - tool_call_name: Optional[str] = None - parent_message_id: Optional[str] = None - delta: Optional[str] = None + tool_call_id: str | None = None + tool_call_name: str | None = None + parent_message_id: str | None = None + delta: str | None = None class ToolCallResultEvent(BaseEvent): """ Event containing the result of a tool call. """ message_id: str - type: Literal[EventType.TOOL_CALL_RESULT] + type: Literal[EventType.TOOL_CALL_RESULT] = EventType.TOOL_CALL_RESULT # pyright: ignore[reportIncompatibleVariableOverride] tool_call_id: str content: str - role: Optional[Literal["tool"]] = None + role: Literal["tool"] | None = None class ThinkingStartEvent(BaseEvent): """ Event indicating the start of a thinking step event. """ - type: Literal[EventType.THINKING_START] - title: Optional[str] = None + type: Literal[EventType.THINKING_START] = EventType.THINKING_START # pyright: ignore[reportIncompatibleVariableOverride] + title: str | None = None class ThinkingEndEvent(BaseEvent): """ Event indicating the end of a thinking step event. """ - type: Literal[EventType.THINKING_END] + type: Literal[EventType.THINKING_END] = EventType.THINKING_END # pyright: ignore[reportIncompatibleVariableOverride] class StateSnapshotEvent(BaseEvent): """ @@ -195,7 +193,7 @@ class RawEvent(BaseEvent): """ type: Literal[EventType.RAW] = EventType.RAW # pyright: ignore[reportIncompatibleVariableOverride] event: Any - source: Optional[str] = None + source: str | None = None class CustomEvent(BaseEvent): @@ -223,7 +221,7 @@ class RunFinishedEvent(BaseEvent): type: Literal[EventType.RUN_FINISHED] = EventType.RUN_FINISHED # pyright: ignore[reportIncompatibleVariableOverride] thread_id: str run_id: str - result: Optional[Any] = None + result: Any = None class RunErrorEvent(BaseEvent): @@ -232,7 +230,7 @@ class RunErrorEvent(BaseEvent): """ type: Literal[EventType.RUN_ERROR] = EventType.RUN_ERROR # pyright: ignore[reportIncompatibleVariableOverride] message: str - code: Optional[str] = None + code: str | None = None class StepStartedEvent(BaseEvent): @@ -252,26 +250,26 @@ class StepFinishedEvent(BaseEvent): Event = Annotated[ - Union[ - TextMessageStartEvent, - TextMessageContentEvent, - TextMessageEndEvent, - TextMessageChunkEvent, - ToolCallStartEvent, - ToolCallArgsEvent, - ToolCallEndEvent, - ToolCallChunkEvent, - ToolCallResultEvent, - StateSnapshotEvent, - StateDeltaEvent, - MessagesSnapshotEvent, - RawEvent, - CustomEvent, - RunStartedEvent, - RunFinishedEvent, - RunErrorEvent, - StepStartedEvent, - StepFinishedEvent, - ], + TextMessageStartEvent | + TextMessageContentEvent | + TextMessageEndEvent | + TextMessageChunkEvent | + ToolCallStartEvent | + ToolCallArgsEvent | + ToolCallEndEvent | + ToolCallChunkEvent | + ToolCallResultEvent | + ThinkingStartEvent | + ThinkingEndEvent | + StateSnapshotEvent | + StateDeltaEvent | + MessagesSnapshotEvent | + RawEvent | + CustomEvent | + RunStartedEvent | + RunFinishedEvent | + RunErrorEvent | + StepStartedEvent | + StepFinishedEvent, Field(discriminator="type") ] diff --git a/python-sdk/ag_ui/core/types.py b/python-sdk/ag_ui/core/types.py index 0cbeddc5..ffc54978 100644 --- a/python-sdk/ag_ui/core/types.py +++ b/python-sdk/ag_ui/core/types.py @@ -1,8 +1,9 @@ """ This module contains the types for the Agent User Interaction Protocol Python SDK. """ +from __future__ import annotations -from typing import Annotated, Any, List, Literal, Optional, Union +from typing import Annotated, Any, List, Literal from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel @@ -42,8 +43,8 @@ class BaseMessage(ConfiguredBaseModel): """ id: str role: str - content: Optional[str] = None - name: Optional[str] = None + content: str | None = None + name: str | None = None class DeveloperMessage(BaseMessage): @@ -51,7 +52,7 @@ class DeveloperMessage(BaseMessage): A developer message. """ role: Literal["developer"] = "developer" # pyright: ignore[reportIncompatibleVariableOverride] - content: str + content: str # pyright: ignore[reportIncompatibleVariableOverride,reportGeneralTypeIssues] class SystemMessage(BaseMessage): @@ -59,7 +60,7 @@ class SystemMessage(BaseMessage): A system message. """ role: Literal["system"] = "system" # pyright: ignore[reportIncompatibleVariableOverride] - content: str + content: str # pyright: ignore[reportIncompatibleVariableOverride,reportGeneralTypeIssues] class AssistantMessage(BaseMessage): @@ -67,7 +68,7 @@ class AssistantMessage(BaseMessage): An assistant message. """ role: Literal["assistant"] = "assistant" # pyright: ignore[reportIncompatibleVariableOverride] - tool_calls: Optional[List[ToolCall]] = None + tool_calls: List[ToolCall] | None = None class UserMessage(BaseMessage): @@ -75,7 +76,7 @@ class UserMessage(BaseMessage): A user message. """ role: Literal["user"] = "user" # pyright: ignore[reportIncompatibleVariableOverride] - content: str + content: str # pyright: ignore[reportIncompatibleVariableOverride,reportGeneralTypeIssues] class ToolMessage(ConfiguredBaseModel): @@ -89,7 +90,7 @@ class ToolMessage(ConfiguredBaseModel): Message = Annotated[ - Union[DeveloperMessage, SystemMessage, AssistantMessage, UserMessage, ToolMessage], + DeveloperMessage | SystemMessage | AssistantMessage | UserMessage | ToolMessage, Field(discriminator="role") ] diff --git a/python-sdk/ag_ui/encoder/__init__.py b/python-sdk/ag_ui/encoder/__init__.py index 030bcc0b..4ae17bc3 100644 --- a/python-sdk/ag_ui/encoder/__init__.py +++ b/python-sdk/ag_ui/encoder/__init__.py @@ -2,6 +2,8 @@ This module contains the EventEncoder class. """ +from __future__ import annotations + from ag_ui.encoder.encoder import EventEncoder, AGUI_MEDIA_TYPE __all__ = ["EventEncoder", "AGUI_MEDIA_TYPE"] diff --git a/python-sdk/ag_ui/encoder/encoder.py b/python-sdk/ag_ui/encoder/encoder.py index f840e3bb..14138cc5 100644 --- a/python-sdk/ag_ui/encoder/encoder.py +++ b/python-sdk/ag_ui/encoder/encoder.py @@ -2,7 +2,13 @@ This module contains the EventEncoder class """ -from ag_ui.core.events import BaseEvent +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ag_ui.core.events import BaseEvent + AGUI_MEDIA_TYPE = "application/vnd.ag-ui.event+proto" @@ -10,8 +16,11 @@ class EventEncoder: """ Encodes Agent User Interaction events. """ - def __init__(self, accept: str = None): - pass + def __init__(self, accept: str | None = None) -> None: + """ + Initializes the EventEncoder. + """ + self.accept = accept def get_content_type(self) -> str: """ diff --git a/python-sdk/tests/test_encoder.py b/python-sdk/tests/test_encoder.py index 2d466c5a..1be941b9 100644 --- a/python-sdk/tests/test_encoder.py +++ b/python-sdk/tests/test_encoder.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import json from datetime import datetime diff --git a/python-sdk/tests/test_events.py b/python-sdk/tests/test_events.py index c73a2537..cbe6f165 100644 --- a/python-sdk/tests/test_events.py +++ b/python-sdk/tests/test_events.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import unittest -import json from datetime import datetime -from pydantic import ValidationError, TypeAdapter +from pydantic import TypeAdapter -from ag_ui.core.types import Message, UserMessage, AssistantMessage, FunctionCall, ToolCall +from ag_ui.core.types import UserMessage, AssistantMessage, FunctionCall, ToolCall from ag_ui.core.events import ( EventType, BaseEvent, diff --git a/python-sdk/tests/test_types.py b/python-sdk/tests/test_types.py index e534aa5a..23b3eca3 100644 --- a/python-sdk/tests/test_types.py +++ b/python-sdk/tests/test_types.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from pydantic import ValidationError from pydantic import TypeAdapter diff --git a/typescript-sdk/integrations/crewai/python/ag_ui_crewai/endpoint.py b/typescript-sdk/integrations/crewai/python/ag_ui_crewai/endpoint.py index 73c492b6..f1df3fb4 100644 --- a/typescript-sdk/integrations/crewai/python/ag_ui_crewai/endpoint.py +++ b/typescript-sdk/integrations/crewai/python/ag_ui_crewai/endpoint.py @@ -1,9 +1,11 @@ """ AG-UI FastAPI server for CrewAI. """ +from __future__ import annotations + import copy import asyncio -from typing import List, Optional +from typing import List from fastapi import FastAPI, Request from fastapi.responses import StreamingResponse @@ -60,7 +62,7 @@ async def create_queue(flow: object) -> asyncio.Queue: return queue -def get_queue(flow: object) -> Optional[asyncio.Queue]: +def get_queue(flow: object) -> asyncio.Queue | None: """Get the queue for a flow.""" queue_id = id(flow) # not using a lock here should be fine diff --git a/typescript-sdk/integrations/crewai/python/ag_ui_crewai/examples/predictive_state_updates.py b/typescript-sdk/integrations/crewai/python/ag_ui_crewai/examples/predictive_state_updates.py index f933d52d..83b55616 100644 --- a/typescript-sdk/integrations/crewai/python/ag_ui_crewai/examples/predictive_state_updates.py +++ b/typescript-sdk/integrations/crewai/python/ag_ui_crewai/examples/predictive_state_updates.py @@ -2,9 +2,10 @@ A demo of predictive state updates. """ +from __future__ import annotations + import json import uuid -from typing import Optional from litellm import completion from crewai.flow.flow import Flow, start, router, listen from ..sdk import ( @@ -43,7 +44,7 @@ class AgentState(CopilotKitState): """ The state of the agent. """ - document: Optional[str] = None + document: str | None = None class PredictiveStateUpdatesFlow(Flow[AgentState]): """ diff --git a/typescript-sdk/integrations/crewai/python/ag_ui_crewai/examples/shared_state.py b/typescript-sdk/integrations/crewai/python/ag_ui_crewai/examples/shared_state.py index ed8dce9e..b3985000 100644 --- a/typescript-sdk/integrations/crewai/python/ag_ui_crewai/examples/shared_state.py +++ b/typescript-sdk/integrations/crewai/python/ag_ui_crewai/examples/shared_state.py @@ -2,9 +2,11 @@ A demo of shared state between the agent and CopilotKit. """ +from __future__ import annotations + import json from enum import Enum -from typing import List, Optional +from typing import List from litellm import completion from pydantic import BaseModel, Field from crewai.flow.flow import Flow, start, router, listen @@ -119,7 +121,7 @@ class AgentState(CopilotKitState): """ The state of the recipe. """ - recipe: Optional[Recipe] = None + recipe: Recipe | None = None class SharedStateFlow(Flow[AgentState]): """ @@ -132,7 +134,7 @@ async def start_flow(self): """ This is the entry point for the flow. """ - print(f"start_flow") + print("start_flow") print(f"self.state: {self.state}") @router(start_flow) diff --git a/typescript-sdk/integrations/crewai/python/ag_ui_crewai/sdk.py b/typescript-sdk/integrations/crewai/python/ag_ui_crewai/sdk.py index be2c714b..f56333de 100644 --- a/typescript-sdk/integrations/crewai/python/ag_ui_crewai/sdk.py +++ b/typescript-sdk/integrations/crewai/python/ag_ui_crewai/sdk.py @@ -2,8 +2,10 @@ This is a placeholder for the copilotkit_stream function. """ +from __future__ import annotations + import uuid -from typing import List, Any, Optional, Mapping, Dict, Literal, TypedDict +from typing import List, Any, Mapping, Dict, Literal, TypedDict from litellm.types.utils import ( ModelResponse, Choices, @@ -39,7 +41,7 @@ class PredictStateConfig(TypedDict): Predict State Config """ tool_name: str - tool_argument: Optional[str] + tool_argument: str | None async def copilotkit_predict_state( config: Dict[str, PredictStateConfig] @@ -166,7 +168,7 @@ async def copilotkit_stream(response): async def _copilotkit_stream_custom_stream_wrapper(response: CustomStreamWrapper): flow = flow_context.get(None) - message_id: Optional[str] = None + message_id: str | None = None tool_call_id: str = "" content = "" created = 0 diff --git a/typescript-sdk/integrations/langgraph/examples/agents/agentic_chat/agent.py b/typescript-sdk/integrations/langgraph/examples/agents/agentic_chat/agent.py index e09c224a..226c5744 100644 --- a/typescript-sdk/integrations/langgraph/examples/agents/agentic_chat/agent.py +++ b/typescript-sdk/integrations/langgraph/examples/agents/agentic_chat/agent.py @@ -2,14 +2,15 @@ A simple agentic chat flow using LangGraph instead of CrewAI. """ -from typing import Dict, List, Any, Optional +from __future__ import annotations + +from typing import List, Any # Updated imports for LangGraph from langchain_core.runnables import RunnableConfig from langgraph.graph import StateGraph, END, START from langgraph.graph import MessagesState from langgraph.types import Command -from typing_extensions import Literal from langchain_openai import ChatOpenAI from langchain_core.messages import SystemMessage diff --git a/typescript-sdk/integrations/langgraph/examples/agents/agentic_generative_ui/agent.py b/typescript-sdk/integrations/langgraph/examples/agents/agentic_generative_ui/agent.py index c46fb6b9..b1f00140 100644 --- a/typescript-sdk/integrations/langgraph/examples/agents/agentic_generative_ui/agent.py +++ b/typescript-sdk/integrations/langgraph/examples/agents/agentic_generative_ui/agent.py @@ -2,9 +2,10 @@ An example demonstrating agentic generative UI using LangGraph. """ -import json +from __future__ import annotations + import asyncio -from typing import Dict, List, Any, Optional, Literal +from typing import List, Any # LangGraph imports from langchain_core.runnables import RunnableConfig from langgraph.graph import StateGraph, END, START diff --git a/typescript-sdk/integrations/langgraph/examples/agents/human_in_the_loop/agent.py b/typescript-sdk/integrations/langgraph/examples/agents/human_in_the_loop/agent.py index 393d2254..c94ec581 100644 --- a/typescript-sdk/integrations/langgraph/examples/agents/human_in_the_loop/agent.py +++ b/typescript-sdk/integrations/langgraph/examples/agents/human_in_the_loop/agent.py @@ -2,6 +2,8 @@ A LangGraph implementation of the human-in-the-loop agent. """ +from __future__ import annotations + import json from typing import Dict, List, Any @@ -11,7 +13,6 @@ from langgraph.types import Command, interrupt from langgraph.graph import MessagesState -from copilotkit.langgraph import copilotkit_emit_state, copilotkit_interrupt # LLM imports from langchain_openai import ChatOpenAI diff --git a/typescript-sdk/integrations/langgraph/examples/agents/predictive_state_updates/agent.py b/typescript-sdk/integrations/langgraph/examples/agents/predictive_state_updates/agent.py index 325f0014..12d05860 100644 --- a/typescript-sdk/integrations/langgraph/examples/agents/predictive_state_updates/agent.py +++ b/typescript-sdk/integrations/langgraph/examples/agents/predictive_state_updates/agent.py @@ -2,9 +2,10 @@ A demo of predictive state updates using LangGraph. """ -import json +from __future__ import annotations + import uuid -from typing import Dict, List, Any, Optional +from typing import List, Any # LangGraph imports from langchain_core.runnables import RunnableConfig @@ -45,7 +46,7 @@ class AgentState(MessagesState): """ The state of the agent. """ - document: Optional[str] = None + document: str | None = None tools: List[Any] diff --git a/typescript-sdk/integrations/langgraph/examples/agents/shared_state/agent.py b/typescript-sdk/integrations/langgraph/examples/agents/shared_state/agent.py index 02fd4a09..b67b0e09 100644 --- a/typescript-sdk/integrations/langgraph/examples/agents/shared_state/agent.py +++ b/typescript-sdk/integrations/langgraph/examples/agents/shared_state/agent.py @@ -2,9 +2,11 @@ A demo of shared state between the agent and CopilotKit using LangGraph. """ +from __future__ import annotations + import json from enum import Enum -from typing import Dict, List, Any, Optional +from typing import Dict, List, Any # LangGraph imports from langchain_core.runnables import RunnableConfig @@ -113,7 +115,7 @@ class AgentState(MessagesState): """ The state of the recipe. """ - recipe: Optional[Dict[str, Any]] = None + recipe: Dict[str, Any] | None = None tools: List[Any] diff --git a/typescript-sdk/integrations/langgraph/examples/agents/tool_based_generative_ui/agent.py b/typescript-sdk/integrations/langgraph/examples/agents/tool_based_generative_ui/agent.py index a7c025a0..1db59cb3 100644 --- a/typescript-sdk/integrations/langgraph/examples/agents/tool_based_generative_ui/agent.py +++ b/typescript-sdk/integrations/langgraph/examples/agents/tool_based_generative_ui/agent.py @@ -2,7 +2,9 @@ An example demonstrating tool-based generative UI using LangGraph. """ -from typing import Dict, List, Any, Optional +from __future__ import annotations + +from typing import List, Any # LangGraph imports from langchain_core.runnables import RunnableConfig diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/agent.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/agent.py index 310a8543..7712b7f9 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/agent.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/agent.py @@ -1,6 +1,8 @@ +from __future__ import annotations + import uuid import json -from typing import Optional, List, Any, Union, AsyncGenerator, Generator +from typing import List, Any, AsyncGenerator, Generator from langgraph.graph.state import CompiledStateGraph from langchain.schema import BaseMessage, SystemMessage @@ -55,35 +57,34 @@ ThinkingStartEvent, ThinkingEndEvent, ) -from ag_ui.encoder import EventEncoder -ProcessedEvents = Union[ - TextMessageStartEvent, - TextMessageContentEvent, - TextMessageEndEvent, - ToolCallStartEvent, - ToolCallArgsEvent, - ToolCallEndEvent, - StateSnapshotEvent, - StateDeltaEvent, - MessagesSnapshotEvent, - RawEvent, - CustomEvent, - RunStartedEvent, - RunFinishedEvent, - RunErrorEvent, - StepStartedEvent, - StepFinishedEvent, -] +ProcessedEvents = ( + TextMessageStartEvent | + TextMessageContentEvent | + TextMessageEndEvent | + ToolCallStartEvent | + ToolCallArgsEvent | + ToolCallEndEvent | + StateSnapshotEvent | + StateDeltaEvent | + MessagesSnapshotEvent | + RawEvent | + CustomEvent | + RunStartedEvent | + RunFinishedEvent | + RunErrorEvent | + StepStartedEvent | + StepFinishedEvent +) class LangGraphAgent: - def __init__(self, *, name: str, graph: CompiledStateGraph, description: Optional[str] = None, config: Union[Optional[RunnableConfig], dict] = None): + def __init__(self, *, name: str, graph: CompiledStateGraph, description: str | None = None, config: RunnableConfig | dict | None = None): self.name = name self.description = description self.graph = graph self.config = config or {} self.messages_in_process: MessagesInProgressRecord = {} - self.active_run: Optional[RunMetadata] = None + self.active_run: RunMetadata | None = None self.constant_schema_keys = ['messages', 'tools'] def _dispatch_event(self, event: ProcessedEvents) -> str: @@ -358,7 +359,7 @@ async def prepare_regenerate_stream( # pylint: disable=too-many-arguments "config": config } - def get_message_in_progress(self, run_id: str) -> Optional[MessageInProgress]: + def get_message_in_progress(self, run_id: str) -> MessageInProgress | None: return self.messages_in_process.get(run_id) def set_message_in_progress(self, run_id: str, data: MessageInProgress): @@ -604,7 +605,7 @@ async def _handle_single_event(self, event: Any, state: State) -> AsyncGenerator yield self._dispatch_event( StateSnapshotEvent(type=EventType.STATE_SNAPSHOT, snapshot=self.get_state_snapshot(state), raw_event=event) ) - + yield self._dispatch_event( CustomEvent(type=EventType.CUSTOM, name=event["name"], value=event["data"], raw_event=event) ) diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/endpoint.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/endpoint.py index 89c6e06b..519a4cd3 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/endpoint.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/endpoint.py @@ -1,4 +1,6 @@ -from fastapi import FastAPI, HTTPException, Request +from __future__ import annotations + +from fastapi import FastAPI, Request from fastapi.responses import StreamingResponse from ag_ui.core.types import RunAgentInput diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/agentic_chat.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/agentic_chat.py index 30c31a17..b8865ebe 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/agentic_chat.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/agentic_chat.py @@ -2,14 +2,15 @@ A simple agentic chat flow using LangGraph instead of CrewAI. """ -from typing import Dict, List, Any, Optional +from __future__ import annotations + +from typing import List, Any # Updated imports for LangGraph from langchain_core.runnables import RunnableConfig from langgraph.graph import StateGraph, END, START from langgraph.graph import MessagesState from langgraph.types import Command -from typing_extensions import Literal from langchain_openai import ChatOpenAI from langchain_core.messages import SystemMessage from langgraph.checkpoint.memory import MemorySaver diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/agentic_generative_ui.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/agentic_generative_ui.py index d3047220..86ab13e1 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/agentic_generative_ui.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/agentic_generative_ui.py @@ -2,9 +2,10 @@ An example demonstrating agentic generative UI using LangGraph. """ -import json +from __future__ import annotations + import asyncio -from typing import Dict, List, Any, Optional, Literal +from typing import List, Any # LangGraph imports from langchain_core.runnables import RunnableConfig from langgraph.graph import StateGraph, END, START diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/predictive_state_updates.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/predictive_state_updates.py index a7b43574..2901fbc6 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/predictive_state_updates.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/predictive_state_updates.py @@ -2,9 +2,10 @@ A demo of predictive state updates using LangGraph. """ -import json +from __future__ import annotations + import uuid -from typing import Dict, List, Any, Optional +from typing import List, Any # LangGraph imports from langchain_core.runnables import RunnableConfig @@ -46,7 +47,7 @@ class AgentState(MessagesState): """ The state of the agent. """ - document: Optional[str] = None + document: str | None = None tools: List[Any] diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/shared_state.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/shared_state.py index 493bbee0..6d56223a 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/shared_state.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/shared_state.py @@ -2,9 +2,11 @@ A demo of shared state between the agent and CopilotKit using LangGraph. """ +from __future__ import annotations + import json from enum import Enum -from typing import Dict, List, Any, Optional +from typing import Dict, List, Any # LangGraph imports from langchain_core.runnables import RunnableConfig @@ -107,7 +109,7 @@ class AgentState(MessagesState): """ The state of the recipe. """ - recipe: Optional[Dict[str, Any]] = None + recipe: Dict[str, Any] | None = None tools: List[Any] diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/tool_based_generative_ui.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/tool_based_generative_ui.py index b286c4db..21ace5cd 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/tool_based_generative_ui.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/examples/agents/tool_based_generative_ui.py @@ -2,7 +2,9 @@ An example demonstrating tool-based generative UI using LangGraph. """ -from typing import Dict, List, Any, Optional +from __future__ import annotations + +from typing import List, Any # LangGraph imports from langchain_core.runnables import RunnableConfig diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/types.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/types.py index 7d08d6bf..346d7aac 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/types.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/types.py @@ -1,7 +1,11 @@ -from typing import TypedDict, Optional, List, Any, Dict, Union, Literal -from typing_extensions import NotRequired +from __future__ import annotations + +from typing import Any, Dict, List, Literal, TypedDict, Union from enum import Enum +from typing_extensions import NotRequired + + class LangGraphEventTypes(str, Enum): OnChainStart = "on_chain_start" OnChainStream = "on_chain_stream" @@ -23,34 +27,34 @@ class CustomEventNames(str, Enum): State = Dict[str, Any] SchemaKeys = TypedDict("SchemaKeys", { - "input": NotRequired[Optional[List[str]]], - "output": NotRequired[Optional[List[str]]], - "config": NotRequired[Optional[List[str]]] + "input": NotRequired[List[str] | None], + "output": NotRequired[List[str] | None], + "config": NotRequired[List[str] | None], }) ThinkingProcess = TypedDict("ThinkingProcess", { "index": int, - "type": NotRequired[Optional[Literal['text']]], + "type": NotRequired[Literal['text'] | None], }) MessageInProgress = TypedDict("MessageInProgress", { "id": str, - "tool_call_id": NotRequired[Optional[str]], - "tool_call_name": NotRequired[Optional[str]] + "tool_call_id": NotRequired[str | None], + "tool_call_name": NotRequired[str | None] }) RunMetadata = TypedDict("RunMetadata", { "id": str, - "schema_keys": NotRequired[Optional[SchemaKeys]], - "node_name": NotRequired[Optional[str]], - "prev_node_name": NotRequired[Optional[str]], + "schema_keys": NotRequired[SchemaKeys | None], + "node_name": NotRequired[str | None], + "prev_node_name": NotRequired[str | None], "exiting_node": NotRequired[bool], - "manually_emitted_state": NotRequired[Optional[State]], - "thread_id": NotRequired[Optional[ThinkingProcess]], - "thinking_process": NotRequired[Optional[str]] + "manually_emitted_state": NotRequired[State | None], + "thread_id": NotRequired[ThinkingProcess | None], + "thinking_process": NotRequired[str | None], }) -MessagesInProgressRecord = Dict[str, Optional[MessageInProgress]] +MessagesInProgressRecord = Dict[str, MessageInProgress | None] ToolCall = TypedDict("ToolCall", { "id": str, diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/utils.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/utils.py index c1c50466..70559041 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/utils.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/utils.py @@ -1,6 +1,8 @@ +from __future__ import annotations + import json import re -from typing import List, Any, Dict, Union +from typing import List, Any, Dict from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, SystemMessage, ToolMessage from ag_ui.core import ( @@ -26,7 +28,7 @@ def get_stream_payload_input( mode: str, state: State, schema_keys: SchemaKeys, -) -> Union[State, None]: +) -> State | None: input_payload = state if mode == "start" else None if input_payload and schema_keys and schema_keys.get("input"): input_payload = filter_object_by_schema_keys(input_payload, [*DEFAULT_SCHEMA_KEYS, *schema_keys["input"]]) diff --git a/typescript-sdk/integrations/llamaindex/server-py/server/routers/shared_state.py b/typescript-sdk/integrations/llamaindex/server-py/server/routers/shared_state.py index a81d5db2..21c6d99f 100644 --- a/typescript-sdk/integrations/llamaindex/server-py/server/routers/shared_state.py +++ b/typescript-sdk/integrations/llamaindex/server-py/server/routers/shared_state.py @@ -1,4 +1,6 @@ -from typing import Literal, List +from __future__ import annotations + +from typing import List from pydantic import BaseModel from llama_index.core.workflow import Context diff --git a/typescript-sdk/integrations/server-starter-all-features/server/python/example_server/agentic_chat.py b/typescript-sdk/integrations/server-starter-all-features/server/python/example_server/agentic_chat.py index 0680d445..d43a070e 100644 --- a/typescript-sdk/integrations/server-starter-all-features/server/python/example_server/agentic_chat.py +++ b/typescript-sdk/integrations/server-starter-all-features/server/python/example_server/agentic_chat.py @@ -1,6 +1,7 @@ """ Agentic chat endpoint for the AG-UI protocol. """ +from __future__ import annotations import uuid import asyncio @@ -23,7 +24,6 @@ ToolCall, AssistantMessage ) -from ag_ui.core.events import TextMessageChunkEvent from ag_ui.encoder import EventEncoder async def agentic_chat_endpoint(input_data: RunAgentInput, request: Request):