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 6d5cdc934..034c77978 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 836570b6a..6a2fbfd8e 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 000000000..fdf72ee0c --- /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 7e909ad5b..33985d39f 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 af1415d7b..c1ee37073 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 0cbeddc52..ffc549788 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 030bcc0b3..4ae17bc34 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 f840e3bb8..14138cc5e 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 2d466c5a4..1be941b92 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 c73a2537c..cbe6f1655 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 e534aa5ab..23b3eca3c 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 73c492b6c..f1df3fb44 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 f933d52d6..83b55616e 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 ed8dce9ee..b39850000 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 be2c714bd..f56333de5 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 e09c224a6..226c57446 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 c46fb6b97..b1f001404 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 393d2254e..c94ec5815 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 325f0014e..12d058600 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 02fd4a099..b67b0e09d 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 a7c025a02..1db59cb34 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 310a85436..7712b7f9f 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 89c6e06be..519a4cd37 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 30c31a177..b8865ebe7 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 d3047220a..86ab13e1f 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 a7b435741..2901fbc6b 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 493bbee05..6d56223a0 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 b286c4dbf..21ace5cd5 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 7d08d6bf3..346d7aac1 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 c1c50466f..70559041e 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 a81d5db25..21c6d99fc 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 0680d4451..d43a070e1 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):