Skip to content

pydantic_ai.ui.vercel_ai

Vercel AI protocol adapter for Pydantic AI agents.

This module provides classes for integrating Pydantic AI agents with the Vercel AI protocol, enabling streaming event-based communication for interactive AI applications.

Converted to Python from: https://github.com/vercel/ai/blob/ai%405.0.34/packages/ai/src/ui/ui-messages.ts

VercelAIAdapter

Bases: UIAdapter[RequestData, UIMessage, BaseChunk, AgentDepsT, OutputDataT]

UI adapter for the Vercel AI protocol.

Attributes

conversation_id

Conversation ID from the top-level id field of the Vercel AI request body (the chat ID).

Type: str | None

deferred_tool_results

Extract deferred tool results from Vercel AI messages with approval responses.

Type: DeferredToolResults | None

messages

Pydantic AI messages from the Vercel AI run input.

Type: list[ModelMessage]

sdk_version

Vercel AI SDK version to target. Default is 5 for backwards compatibility.

Setting sdk_version=6 enables tool approval streaming for human-in-the-loop workflows. sdk_version=7 emits the same wire as 6 (v7’s data-stream protocol equals v6’s); it is accepted so the value reflects the client’s real SDK major and reserves it for future v7-only chunks.

Type: Literal[5, 6, 7] Default: 5

server_message_id

Optional server-generated message ID to include in the StartChunk.

Type: str | None Default: None

Methods

build_event_stream

def build_event_stream(

) -> UIEventStream[RequestData, BaseChunk, AgentDepsT, OutputDataT]

Build a Vercel AI event stream transformer.

Returns

UIEventStream[RequestData, BaseChunk, AgentDepsT, OutputDataT]

build_run_input

@classmethod

def build_run_input(cls, body: bytes) -> RequestData

Build a Vercel AI run input object from the request body.

Returns

RequestData

dispatch_request

@async

@classmethod

def dispatch_request(
    cls,
    request: Request,
    *,
    agent: AbstractAgent[DispatchDepsT, DispatchOutputDataT],
    sdk_version: Literal[5, 6, 7] = 5,
    server_message_id: str | None = None,
    message_history: Sequence[ModelMessage] | None = None,
    deferred_tool_results: DeferredToolResults | None = None,
    conversation_id: str | None = None,
    run_id: str | None = None,
    model: Model | KnownModelName | str | None = None,
    instructions: _instructions.AgentInstructions[DispatchDepsT] = None,
    deps: DispatchDepsT = None,
    output_type: OutputSpec[Any] | None = None,
    model_settings: ModelSettings | None = None,
    usage_limits: UsageLimits | None = None,
    usage: RunUsage | None = None,
    metadata: AgentMetadata[DispatchDepsT] | None = None,
    infer_name: bool = True,
    toolsets: Sequence[AbstractToolset[DispatchDepsT]] | None = None,
    capabilities: Sequence[AbstractCapability[DispatchDepsT]] | None = None,
    on_complete: OnCompleteFunc[BaseChunk] | None = None,
    on_cancel: OnCancelFunc[BaseChunk] | None = None,
    manage_system_prompt: Literal['server', 'client'] = 'server',
    allowed_file_url_schemes: frozenset[str] = frozenset({'http', 'https'}),
    allowed_file_url_force_download: frozenset[ForceDownloadMode] = frozenset(),
    allow_uploaded_files: bool = False,
    preserve_file_data: bool | None = None,
    **kwargs: Any,
) -> Response

Extends dispatch_request with Vercel AI-specific parameters.

preserve_file_data is a deprecated alias for allow_uploaded_files.

Returns

Response

dump_messages

@classmethod

def dump_messages(
    cls,
    messages: Sequence[ModelMessage],
    *,
    generate_message_id: Callable[[ModelRequest | ModelResponse, Literal['system', 'user', 'assistant'], int], str] | None = None,
    sdk_version: Literal[5, 6, 7] = 5,
) -> list[UIMessage]

Transform Pydantic AI messages into Vercel AI messages.

Note: The round-trip dump_messages -> load_messages is not fully lossless for tool results. Successful, failed, and denied results each round-trip via their own part type (ToolOutputAvailablePart / ToolOutputErrorPart / ToolOutputDeniedPart), but a RetryPromptPart becomes a ToolReturnPart with outcome='failed' on reload (or a user text part when it has no tool_name), since the protocol has no separate retry concept — both a retry prompt and a ToolFailed result map to ToolOutputErrorPart. A reloaded retry is therefore presented to the model as a definitive failure rather than a request to correct and retry; keep the conversation in-process rather than persisting through the Vercel AI wire format if you need retry semantics to survive a round-trip.

Tool calls lose one thing too: ToolCallPart.args that don’t parse as a JSON object are rewritten to {'INVALID_JSON': '<raw args>'} (see args_as_dict), so the raw string is no longer recoverable as args on reload.

When sdk_version=6, tool calls that have no corresponding result in the message history are automatically detected as deferred and emitted with state='approval-requested', so the frontend can render approve/reject buttons on reload. On v5, such tool calls are emitted with state='input-available' (approval states are v6-only).

Returns

list[UIMessage] — A list of UIMessage objects in Vercel AI format

Parameters

messages : Sequence[ModelMessage]

A sequence of ModelMessage objects to convert

generate_message_id : Callable[[ModelRequest | ModelResponse, Literal[‘system’, ‘user’, ‘assistant’], int], str] | None Default: None

Optional custom function to generate message IDs. If provided, it receives the message, the role (‘system’, ‘user’, or ‘assistant’), and the message index (incremented per UIMessage appended), and should return a unique string ID. If not provided, uses provider_response_id for responses, run_id-based IDs for messages with run_id, or a deterministic UUID5 fallback.

sdk_version : Literal[5, 6, 7] Default: 5

Vercel AI SDK version to target: 5, 6, or 7. Defaults to 5 for backwards compatibility. Set to 6 to emit tool approval parts for deferred tool calls; 7 emits identically to 6 (v7’s data-stream protocol equals v6’s).

from_request

@async

@classmethod

def from_request(
    cls,
    request: Request,
    *,
    agent: AbstractAgent[AgentDepsT, OutputDataT],
    sdk_version: Literal[5, 6, 7] = 5,
    server_message_id: str | None = None,
    manage_system_prompt: Literal['server', 'client'] = 'server',
    allowed_file_url_schemes: frozenset[str] = frozenset({'http', 'https'}),
    allowed_file_url_force_download: frozenset[ForceDownloadMode] = frozenset(),
    allow_uploaded_files: bool = False,
    preserve_file_data: bool | None = None,
    **kwargs: Any,
) -> VercelAIAdapter[AgentDepsT, OutputDataT]

Extends from_request with Vercel AI-specific parameters.

preserve_file_data is a deprecated alias for allow_uploaded_files.

Returns

VercelAIAdapter[AgentDepsT, OutputDataT]

load_messages

@classmethod

def load_messages(cls, messages: Sequence[UIMessage]) -> list[ModelMessage]

Transform Vercel AI messages into Pydantic AI messages.

Returns

list[ModelMessage]

VercelAIEventStream

Bases: UIEventStream[RequestData, BaseChunk, AgentDepsT, OutputDataT]

UI event stream transformer for the Vercel AI protocol.

Attributes

sdk_version

Vercel AI SDK version to target. Setting to 6 enables tool approval streaming; 7 emits the same wire as 6 (v7’s data-stream protocol equals v6’s).

Type: Literal[5, 6, 7] Default: 5

server_message_id

Optional server-generated message ID to include in the StartChunk.

Type: str | None Default: None

Vercel AI request types (UI messages).

Converted to Python from: https://github.com/vercel/ai/blob/ai%406.0.57/packages/ai/src/ui/ui-messages.ts

Tool approval types (ToolApprovalRequested, ToolApprovalResponded) require AI SDK v6 or later.

BaseUIPart

Bases: CamelBaseModel, ABC

Abstract base class for all UI parts.

DataUIPart

Bases: BaseUIPart

Data part with dynamic type based on data name.

DynamicToolApprovalRequestedPart

Bases: BaseUIPart

Dynamic tool part in approval-requested state (awaiting user decision).

DynamicToolApprovalRespondedPart

Bases: BaseUIPart

Dynamic tool part in approval-responded state (user approved/denied, execution pending).

DynamicToolInputAvailablePart

Bases: BaseUIPart

Dynamic tool part in input-available state.

DynamicToolInputStreamingPart

Bases: BaseUIPart

Dynamic tool part in input-streaming state.

DynamicToolOutputAvailablePart

Bases: BaseUIPart

Dynamic tool part in output-available state.

DynamicToolOutputDeniedPart

Bases: BaseUIPart

Dynamic tool part in output-denied state (tool was denied, terminal state).

DynamicToolOutputErrorPart

Bases: BaseUIPart

Dynamic tool part in output-error state.

FileUIPart

Bases: BaseUIPart

A file part of a message.

Attributes

filename

Optional filename of the file.

Type: str | None Default: None

media_type

IANA media type of the file. @see https://www.iana.org/assignments/media-types/media-types.xhtml

Type: str

provider_metadata

The provider metadata.

Type: ProviderMetadata | None Default: None

url

The URL of the file. It can either be a URL to a hosted file or a Data URL.

Type: str

ReasoningUIPart

Bases: BaseUIPart

A reasoning part of a message.

Attributes

provider_metadata

The provider metadata.

Type: ProviderMetadata | None Default: None

state

The state of the reasoning part.

Type: Literal[‘streaming’, ‘done’] | None Default: None

text

The reasoning text.

Type: str

RegenerateMessage

Bases: CamelBaseModel

Ask the agent to regenerate a message.

SourceDocumentUIPart

Bases: BaseUIPart

A document source part of a message.

SourceUrlUIPart

Bases: BaseUIPart

A source part of a message.

StepStartUIPart

Bases: BaseUIPart

A step boundary part of a message.

SubmitMessage

Bases: CamelBaseModel

Submit message request.

TextUIPart

Bases: BaseUIPart

A text part of a message.

Attributes

provider_metadata

The provider metadata.

Type: ProviderMetadata | None Default: None

state

The state of the text part.

Type: Literal[‘streaming’, ‘done’] | None Default: None

text

The text content.

Type: str

ToolApprovalRequested

Bases: CamelBaseModel

Tool approval in requested state (awaiting user response).

Attributes

id

The approval request ID.

Type: str

ToolApprovalRequestedPart

Bases: BaseUIPart

Tool part in approval-requested state (awaiting user decision).

ToolApprovalResponded

Bases: CamelBaseModel

Tool approval in responded state (user has approved or denied).

Attributes

approved

Whether the user approved the tool call.

Deliberately strict: in Pydantic’s default lax mode {'approved': 1} or {'approved': 'true'} would coerce to an approval, and this field is the client-controlled gate on tools declared requires_approval=True. A non-boolean value fails validation — and so rejects the whole request — instead of silently executing the call (#6922).

ToolApproval is an undiscriminated union, so rejecting here only denies because CamelBaseModel’s extra='forbid' stops the part re-matching ToolApprovalRequested (which upstream declares approved?: never). Relaxing either would reopen the gate.

Type: StrictBool

id

The approval request ID.

Type: str

reason

Optional reason for the approval or denial.

Type: str | None Default: None

ToolApprovalRespondedPart

Bases: BaseUIPart

Tool part in approval-responded state (user approved/denied, execution pending).

ToolInputAvailablePart

Bases: BaseUIPart

Tool part in input-available state.

ToolInputStreamingPart

Bases: BaseUIPart

Tool part in input-streaming state.

ToolOutputAvailablePart

Bases: BaseUIPart

Tool part in output-available state.

ToolOutputDeniedPart

Bases: BaseUIPart

Tool part in output-denied state (tool was denied, terminal state).

ToolOutputErrorPart

Bases: BaseUIPart

Tool part in output-error state.

UIMessage

Bases: CamelBaseModel

A message as displayed in the UI by Vercel AI Elements.

Attributes

id

A unique identifier for the message.

Type: str

metadata

The metadata of the message.

Type: Any | None Default: None

parts

The parts of the message. Use this for rendering the message in the UI. System messages should be avoided (set the system prompt on the server instead). They can have text parts. User messages can have text parts and file parts. Assistant messages can have text, reasoning, tool invocation, and file parts.

Type: list[UIMessagePart]

role

The role of the message.

Type: Literal[‘system’, ‘user’, ‘assistant’]

DynamicToolUIPart

Union of all dynamic tool part types.

Default: DynamicToolInputStreamingPart | DynamicToolInputAvailablePart | DynamicToolOutputAvailablePart | DynamicToolOutputErrorPart | DynamicToolApprovalRequestedPart | DynamicToolApprovalRespondedPart | DynamicToolOutputDeniedPart

ProviderMetadata

Provider metadata.

Default: dict[str, dict[str, JSONValue]]

RequestData

Union of all request data types.

Default: Annotated[SubmitMessage | RegenerateMessage, Discriminator('trigger')]

ToolApproval

Union of tool approval states.

Default: ToolApprovalRequested | ToolApprovalResponded

ToolUIPart

Union of all tool part types.

Default: ToolInputStreamingPart | ToolInputAvailablePart | ToolOutputAvailablePart | ToolOutputErrorPart | ToolApprovalRequestedPart | ToolApprovalRespondedPart | ToolOutputDeniedPart

UIMessagePart

Union of all message part types.

Default: TextUIPart | ReasoningUIPart | ToolUIPart | DynamicToolUIPart | SourceUrlUIPart | SourceDocumentUIPart | FileUIPart | DataUIPart | StepStartUIPart

Vercel AI response types (SSE chunks).

Converted to Python from: https://github.com/vercel/ai/blob/ai%406.0.57/packages/ai/src/ui-message-stream/ui-message-chunks.ts

Tool approval types (ToolApprovalRequestChunk, ToolOutputDeniedChunk) require AI SDK UI v6 or later.

AbortChunk

Bases: BaseChunk

Abort chunk.

BaseChunk

Bases: CamelBaseModel, ABC

Abstract base class for response SSE events.

DataChunk

Bases: BaseChunk

Data chunk with dynamic type.

DoneChunk

Bases: BaseChunk

Done chunk.

ErrorChunk

Bases: BaseChunk

Error chunk.

FileChunk

Bases: BaseChunk

File chunk.

FinishChunk

Bases: BaseChunk

Finish chunk.

FinishStepChunk

Bases: BaseChunk

Finish step chunk.

MessageMetadataChunk

Bases: BaseChunk

Message metadata chunk.

ReasoningDeltaChunk

Bases: BaseChunk

Reasoning delta chunk.

ReasoningEndChunk

Bases: BaseChunk

Reasoning end chunk.

ReasoningStartChunk

Bases: BaseChunk

Reasoning start chunk.

SourceDocumentChunk

Bases: BaseChunk

Source document chunk.

SourceUrlChunk

Bases: BaseChunk

Source URL chunk.

StartChunk

Bases: BaseChunk

Start chunk.

StartStepChunk

Bases: BaseChunk

Start step chunk.

TextDeltaChunk

Bases: BaseChunk

Text delta chunk.

TextEndChunk

Bases: BaseChunk

Text end chunk.

TextStartChunk

Bases: BaseChunk

Text start chunk.

ToolApprovalRequestChunk

Bases: BaseChunk

Tool approval request chunk for human-in-the-loop approval.

Requires AI SDK UI v6 or later.

ToolInputAvailableChunk

Bases: BaseChunk

Tool input available chunk.

ToolInputDeltaChunk

Bases: BaseChunk

Tool input delta chunk.

ToolInputErrorChunk

Bases: BaseChunk

Tool input error chunk.

Requires AI SDK UI v6 or later.

ToolInputStartChunk

Bases: BaseChunk

Tool input start chunk.

ToolOutputAvailableChunk

Bases: BaseChunk

Tool output available chunk.

ToolOutputDeniedChunk

Bases: BaseChunk

Tool output denied chunk when user denies tool execution.

Requires AI SDK UI v6 or later.

ToolOutputErrorChunk

Bases: BaseChunk

Tool output error chunk.

FinishReason

Reason why the model finished generating.

Default: Literal['stop', 'length', 'content-filter', 'tool-calls', 'error', 'other'] | None

ProviderMetadata

Provider metadata.

Default: dict[str, dict[str, JSONValue]]